'use strict';
// Command-preset fallback args.
//
// ccmanager lets providers declare `{args, fallbackArgs}`. When a session
// crashes early (before reaching idle), CTM retries once with fallbackArgs.
// The canonical case is `claude --resume <stale-id>` failing immediately —
// falling back to plain `claude` lets the user keep working.
//
// Design: orthogonal to providers/ (which is scoped to approval detection).
// A "preset" here is a strategy keyed on the primary command + arg patterns,
// producing either a modified arg list or null if no fallback applies.

const PRESETS = [
  // --- Claude Code ---
  {
    id: 'claude-strip-resume',
    match: (cmd, args) => /(^|\/)claude(\s|$)/.test(cmd) && args.includes('--resume'),
    apply: (cmd, args) => _stripFlagWithValue(args, '--resume'),
    reason: 'strip stale --resume after early crash',
  },
  {
    id: 'claude-strip-continue',
    match: (cmd, args) => /(^|\/)claude(\s|$)/.test(cmd) && args.includes('--continue'),
    apply: (cmd, args) => args.filter(a => a !== '--continue'),
    reason: 'strip --continue (session may be unresumable)',
  },
  // --- Codex ---
  {
    id: 'codex-strip-thread',
    match: (cmd, args) => /(^|\/)codex(\s|$)/.test(cmd) && args.includes('--thread'),
    apply: (cmd, args) => _stripFlagWithValue(args, '--thread'),
    reason: 'strip stale --thread',
  },
  {
    id: 'codex-strip-resume-flag',
    match: (cmd, args) => /(^|\/)codex(\s|$)/.test(cmd) && args.includes('resume'),
    apply: (cmd, args) => args.filter(a => a !== 'resume'),
    reason: 'fall back from `codex resume` to fresh `codex`',
  },
  // --- Gemini ---
  {
    id: 'gemini-strip-session',
    match: (cmd, args) => /(^|\/)gemini(\s|$)/.test(cmd) && args.includes('--session'),
    apply: (cmd, args) => _stripFlagWithValue(args, '--session'),
    reason: 'strip stale --session',
  },
  // --- Aider ---
  {
    id: 'aider-strip-restore',
    match: (cmd, args) => /(^|\/)aider(\s|$)/.test(cmd) && args.includes('--restore-chat-history'),
    apply: (cmd, args) => args.filter(a => a !== '--restore-chat-history'),
    reason: 'skip chat history restore',
  },
];

// Remove `--flag value` (two consecutive args) from the list.
function _stripFlagWithValue(args, flag) {
  const out = [];
  for (let i = 0; i < args.length; i++) {
    if (args[i] === flag) { i++; continue; } // skip the value too
    out.push(args[i]);
  }
  return out;
}

// Resolve a fallback for (cmd, args). Returns:
//   { fallbackArgs, presetId, reason } on match
//   null if no preset applies
function resolveFallback(cmd, args) {
  const cmdStr = String(cmd || '');
  const argList = Array.isArray(args) ? args.slice() : [];
  for (const preset of PRESETS) {
    try {
      if (!preset.match(cmdStr, argList)) continue;
    } catch { continue; }
    let fallbackArgs;
    try { fallbackArgs = preset.apply(cmdStr, argList); }
    catch { continue; }
    if (!Array.isArray(fallbackArgs)) continue;
    // Skip no-op fallbacks (preset matched but produced identical args).
    if (fallbackArgs.length === argList.length && fallbackArgs.every((v, i) => v === argList[i])) continue;
    return { fallbackArgs, presetId: preset.id, reason: preset.reason };
  }
  return null;
}

// Minimum uptime to consider a session "healthy enough not to retry".
// ccmanager uses a similar "early exit" heuristic — if the process lasted
// long enough to reach idle, we don't overwrite the user's args on restart.
const EARLY_EXIT_WINDOW_MS = 10_000;

function isEarlyExit({ createdAt, exitedAt }) {
  if (!createdAt) return false;
  const uptime = (exitedAt || Date.now()) - createdAt;
  return uptime < EARLY_EXIT_WINDOW_MS;
}

module.exports = {
  PRESETS,
  resolveFallback,
  isEarlyExit,
  EARLY_EXIT_WINDOW_MS,
};
