const GOA_PREFIX = '@vigthoria-goa:';

// Returns true if `trimmedTail` could still grow into a complete
// "@vigthoria-goa:{...}" marker line once more bytes arrive.
function looksLikePartialGoaMarker(trimmedTail: string): boolean {
  if (!trimmedTail) return false;
  return GOA_PREFIX.startsWith(trimmedTail) || trimmedTail.startsWith(GOA_PREFIX);
}

export function stripGoaFromChunk(chunk: string, carry: string): { visible: string; carry: string } {
  // Same class of bug as the deck-event stripper: a "@vigthoria-goa:{...}"
  // marker line split across two PTY read chunks would previously leak into
  // the visible terminal as raw JSON because this was a stateless per-chunk
  // filter with no carry-over for a trailing partial line.
  const combined = carry + chunk;
  const lines = combined.split('\n');
  const tail = lines.pop() ?? '';

  const keptLines = lines.filter((line) => !line.trim().startsWith(GOA_PREFIX));
  let visible = keptLines.length > 0 ? `${keptLines.join('\n')}\n` : '';

  const trimmedTail = tail.trim();
  if (tail && !looksLikePartialGoaMarker(trimmedTail)) {
    visible += tail;
    return { visible, carry: '' };
  }
  return { visible, carry: tail };
}

export function extractGoaFromChunk(text: string): Record<string, unknown> | null {
  for (const line of text.split('\n')) {
    const trimmed = line.trim();
    if (!trimmed.startsWith(GOA_PREFIX)) continue;
    try {
      return JSON.parse(trimmed.slice(GOA_PREFIX.length)) as Record<string, unknown>;
    } catch {
      return null;
    }
  }
  return null;
}
