'use strict';
// Gemini CLI state detector.
//
// Gemini emits hook events for authoritative state when configured, but users can
// still run without hooks. Keep the PTY fallback from treating TUI footer redraws
// and spinner/status fragments as substantive activity.

const { baseDetector, stripAnsi } = require('./base');

const GEMINI_STATUS_FRAGMENT_RE = /^(?:[\s\d•◦·∙●○✦✧◆◇◐◓◑◒|/\\-]+|Thinking\.{0,3}|Working\.{0,3}|Running\.{0,3}|Responding\.{0,3}|Loading\.{0,3}|esc\s+to\s+(?:cancel|interrupt)|ctrl\+c\s+to\s+(?:quit|cancel)|press\s+enter\s+to\s+send|shift\+enter\s+for\s+newline)$/iu;

// The WORKING subset of the status vocabulary. Two precise signals, both shown
// only mid-generation: the in-flight "esc to cancel/interrupt" hint, and a
// STANDALONE spinner/status line ("✦ Thinking…"). Anchoring the verb to a whole
// status line keeps ordinary prose ("I'm working on the fix") from matching, and
// the idle composer hints ("press enter to send", "ctrl+c to quit") are excluded
// entirely — so it never mislabels an idle session as generating. server.js's
// generating-gate uses this to suppress the idle-notify so a long, output-quiet
// Gemini turn whose composer matches a global prompt pattern is not flagged
// "Needs You". (Gemini has no detectWaitingInput hook, so this is its only guard.)
const GEMINI_INTERRUPT_HINT_RE = /\besc\s+to\s+(?:cancel|interrupt)\b/i;
const GEMINI_WORKING_STATUS_LINE_RE = /^[\s•◦·∙●○✦✧◆◇◐◓◑◒|/\\-]*(?:Thinking|Working|Running|Responding|Loading)\b\.{0,3}\s*$/i;
function detectActivelyGenerating(text) {
  // Split on newlines FIRST (base.stripAnsi drops them), then strip per line.
  return String(text || '').split(/\r?\n/).slice(-12).some(line => {
    const t = stripAnsi(line).trim();
    return GEMINI_INTERRUPT_HINT_RE.test(t) || GEMINI_WORKING_STATUS_LINE_RE.test(t);
  });
}

function isCursorAddressedRedraw(data) {
  const s = String(data || '');
  return (
    /\x1b\[[0-9]+;[0-9]+H/.test(s) &&
    /\x1b\[[0-9;?]*[KJ]/.test(s)
  ) || /\x1b\[\?2026h/.test(s) || /\x1b\[[0-9]+A/.test(s);
}

module.exports = {
  ...baseDetector,
  id: 'gemini',

  isActiveChunk(data) {
    if (!baseDetector.isActiveChunk(data)) return false;
    const stripped = stripAnsi(data).trim();
    if (
      stripped.length <= 100 &&
      GEMINI_STATUS_FRAGMENT_RE.test(stripped) &&
      isCursorAddressedRedraw(data)
    ) {
      return false;
    }
    return true;
  },

  detectActivelyGenerating,
};
