'use strict';
// Registry of per-CLI state detectors.
//
// Each detector exports (at least): id, idleDebounceMs, isActiveChunk(data),
// filterOutput(data). See ./base.js for the contract.
//
// Callers use `getStateDetector(providerId)` which always returns a valid
// detector (falling back to the base detector when no match is found).

const { baseDetector } = require('./base');
const claudeCode = require('./claude-code');
const codex = require('./codex');
const gemini = require('./gemini');
const opencode = require('./opencode');
const cursor = require('./cursor');

// Provider-id → detector. Adding a new provider is just an import + entry.
const _detectors = new Map([
  ['claude-code', claudeCode],
  ['codex', codex],
  ['gemini', gemini],
  ['gemini-cli', gemini],
  ['opencode', opencode],
  ['cursor', cursor],
]);

function getStateDetector(providerId) {
  if (providerId && _detectors.has(providerId)) return _detectors.get(providerId);
  return baseDetector;
}

// Single authoritative "is this session blocked at a LIVE approval/choice widget
// right now?" decision, delegated to the provider's own state detector. This is
// the one place the banner path should ask — replacing global, provider-blind
// content regexes. Hide-unless-confident: returns live only when the detector
// positively confirms an approval/choice widget AND no ready/finished composer is
// on screen (a live widget REPLACES the composer). Unknown providers / detectors
// without a detectWaitingInput hook → {live:false}.
function isSessionAtLivePrompt(providerId, text) {
  const detector = getStateDetector(providerId);
  try {
    const wi = typeof detector.detectWaitingInput === 'function' ? detector.detectWaitingInput(text) : null;
    const reason = wi && wi.reason;
    if (reason !== 'approval' && reason !== 'choice') return { live: false, reason: null };
    const readyComposer = typeof detector.detectReadyComposer === 'function' && detector.detectReadyComposer(text);
    const turnFinished = typeof detector.detectTurnFinished === 'function' && detector.detectTurnFinished(text);
    if (readyComposer || turnFinished) return { live: false, reason: null };
    return { live: true, reason };
  } catch {
    // A detector throwing must never break the caller's idle-notify path; default
    // to not-live (hide-unless-confident).
    return { live: false, reason: null };
  }
}

function registerStateDetector(providerId, detector) {
  if (!providerId || !detector) return;
  _detectors.set(providerId, detector);
}

function listStateDetectors() {
  return Array.from(_detectors.entries()).map(([id, d]) => ({
    providerId: id,
    id: d.id,
    idleDebounceMs: d.idleDebounceMs,
  }));
}

module.exports = {
  getStateDetector,
  isSessionAtLivePrompt,
  registerStateDetector,
  listStateDetectors,
  baseDetector,
};
