'use strict';

const crypto = require('crypto');
const fs = require('fs');

function stripAnsi(text) {
  return String(text || '')
    .replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '')
    .replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '');
}

function normalizeForTerminalSearch(text) {
  return stripAnsi(text)
    .normalize('NFKC')
    .replace(/[*_`#>~]/g, '')
    .replace(/[\x00-\x1f\x7f]/g, ' ')
    .replace(/\s+/g, ' ')
    .trim()
    .toLowerCase();
}

function meaningfulLines(text) {
  return stripAnsi(text)
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);
}

function markerForFinalText(text) {
  const lines = meaningfulLines(text);
  if (lines.length === 0) return '';
  let candidate = lines.find((line) => normalizeForTerminalSearch(line).length >= 24) || lines[0];
  if (normalizeForTerminalSearch(candidate).length < 24 && lines.length > 1) {
    candidate = `${candidate} ${lines[1]}`;
  }
  return normalizeForTerminalSearch(candidate).slice(0, 180);
}

function terminalContainsFinalText(terminalText, finalText) {
  const marker = markerForFinalText(finalText);
  if (!marker) return true;
  return normalizeForTerminalSearch(terminalText).includes(marker);
}

function fingerprintFinalText(text) {
  return crypto.createHash('sha1').update(String(text || '')).digest('hex').slice(0, 16);
}

function _codexAssistantOutputText(content) {
  if (!Array.isArray(content)) return '';
  return content
    .filter((block) => block && block.type === 'output_text' && block.text)
    .map((block) => block.text)
    .join('\n')
    .trim();
}

function codexFinalTextFromEntry(entry) {
  if (!entry || typeof entry !== 'object') return null;
  if (entry.type === 'event_msg' && entry.payload?.type === 'task_complete') {
    const text = String(entry.payload.last_agent_message || '').trim();
    if (text) {
      return {
        text,
        timestamp: entry.timestamp || entry.payload.timestamp || '',
        source: 'task_complete',
      };
    }
  }
  if (entry.type === 'response_item' && entry.payload?.type === 'message' && entry.payload.role === 'assistant') {
    const text = _codexAssistantOutputText(entry.payload.content);
    if (text) {
      return {
        text,
        timestamp: entry.timestamp || '',
        source: 'assistant_message',
      };
    }
  }
  return null;
}

function latestCodexFinalTextFromJsonlText(text) {
  const lines = String(text || '').split(/\r?\n/);
  for (let i = lines.length - 1; i >= 0; i--) {
    const line = lines[i];
    if (!line || !line.trim()) continue;
    let entry;
    try { entry = JSON.parse(line); } catch { continue; }
    const final = codexFinalTextFromEntry(entry);
    if (final) return final;
  }
  return null;
}

function latestCodexFinalTextFromJsonlFile(filePath, options = {}) {
  if (!filePath) return null;
  const maxTailBytes = Math.max(1024, Number(options.maxTailBytes || 8 * 1024 * 1024));
  let st;
  try { st = fs.statSync(filePath); } catch { return null; }
  if (!st || !st.isFile() || st.size <= 0) return null;
  const readSize = Math.min(st.size, maxTailBytes);
  const start = st.size - readSize;
  let fd = null;
  try {
    fd = fs.openSync(filePath, 'r');
    const buf = Buffer.alloc(readSize);
    fs.readSync(fd, buf, 0, readSize, start);
    let text = buf.toString('utf8');
    if (start > 0) {
      const firstNewline = text.indexOf('\n');
      if (firstNewline >= 0) text = text.slice(firstNewline + 1);
    }
    return latestCodexFinalTextFromJsonlText(text);
  } catch {
    return null;
  } finally {
    try { if (fd != null) fs.closeSync(fd); } catch {}
  }
}

module.exports = {
  codexFinalTextFromEntry,
  fingerprintFinalText,
  latestCodexFinalTextFromJsonlFile,
  latestCodexFinalTextFromJsonlText,
  markerForFinalText,
  normalizeForTerminalSearch,
  terminalContainsFinalText,
};
