import fs from "node:fs/promises";
import path from "node:path";
import { capture } from "./capture";
import {
  RECORDER_ACTIONS,
  normalizeAction,
  isManifestLike,
  scanManifestCandidates,
  validateManifestShape,
  type RecorderAction,
  type RecorderManifest
} from "./manifestContract";
import {
  investigateManifestFailure,
  type FailureLane,
  type AI1Mode
} from "./eq";
import { BACKSTAGE_SERIAL, controller } from "./controller";
import { spawn } from "node:child_process";
import { getSettings } from "./mgrSNP";
export { isManifestLike, type RecorderManifest };

export type RecorderResult = {
  ok: boolean;
  action: string;
  filePath: string;
  changed: boolean;
  message: string;
};

type RunResult = {
  dubID: string;
  manifest: RecorderManifest;
  status: "done" | "error";
  result: any;
};

type RecorderState = "STOP" | "RECORD" | "PAUSE";

export type RecorderStatus = {
  state: RecorderState;
  busy: boolean;
  paused: boolean;
  pauseRequested: boolean;
  queueLength: number;
};

type FailureClassification = {
  lane: FailureLane;
  mode: AI1Mode;
  rawError: string;
  normalizedReason: string;
  repairEligible: boolean;
};

const recorderStatus = {
  busy: false,
  paused: false,
  pauseRequested: false
};

const pendingRuns: Array<{ input?: unknown; source: string }> = [];

// ── Recorder state ────────────────────────────────────────────────────────────

function currentStatus(): RecorderStatus {
  return {
    state: getRecorderState(),
    busy: recorderStatus.busy,
    paused: recorderStatus.paused,
    pauseRequested: recorderStatus.pauseRequested,
    queueLength: pendingRuns.length
  };
}

function engagePauseIfRequested(reason = "boundary"): void {
  if (!recorderStatus.pauseRequested) return;
  recorderStatus.pauseRequested = false;
  recorderStatus.paused = true;
  capture.system({ tag: "Recorder", event: "pause_engaged", reason, ...currentStatus() });
}

export function isRecorderBusy(): boolean {
  return recorderStatus.busy;
}

export function getRecorderState(): RecorderState {
  if (recorderStatus.busy) return "RECORD";
  if (recorderStatus.paused) return "PAUSE";
  return "STOP";
}

export function getRecorderStatus(): RecorderStatus {
  return currentStatus();
}

export function requestRecorderPause(): RecorderStatus {
  if (recorderStatus.busy) {
    recorderStatus.pauseRequested = true;
    capture.system({ tag: "Recorder", event: "pause_requested", ...currentStatus() });
  } else {
    recorderStatus.paused = true;
    recorderStatus.pauseRequested = false;
    capture.system({ tag: "Recorder", event: "pause_entered_idle", ...currentStatus() });
  }
  return currentStatus();
}

export function resumeRecorder(): RecorderStatus {
  recorderStatus.paused = false;
  recorderStatus.pauseRequested = false;
  capture.system({ tag: "Recorder", event: "resume_requested", ...currentStatus() });
  return currentStatus();
}

export async function cancelRemainingRecorderTasks(): Promise<RecorderStatus> {
  pendingRuns.length = 0;

  const tape = await capture.tape.load();
  const cancelIDs = tape
    .filter((item: any) => item.recorderStatus === "YES" && isManifestLike(item.manifest))
    .map((item: any) => item.dubID);

  if (cancelIDs.length) await capture.tape.markRetrieved(cancelIDs);

  recorderStatus.pauseRequested = false;
  recorderStatus.paused = true;

  capture.system({
    tag: "Recorder",
    event: "remaining_tasks_cancelled",
    cancelledQueue: 0,
    cancelledTape: cancelIDs.length,
    ...currentStatus()
  });

  return currentStatus();
}

export function setRecorderPaused(paused: boolean): void {
  if (paused) requestRecorderPause();
  else resumeRecorder();
}

// ── File resolution / primitives ──────────────────────────────────────────────

function resolveFile(filePath: string): string {
  return controller.resolveProjectPath(filePath);
}

async function readText(filePath: string): Promise<string> {
  return await fs.readFile(filePath, "utf8");
}

async function readTextMaybe(filePath: string): Promise<string | null> {
  try {
    return await fs.readFile(filePath, "utf8");
  } catch {
    return null;
  }
}

async function writeText(filePath: string, content: string): Promise<void> {
  await fs.mkdir(path.dirname(filePath), { recursive: true });
  await fs.writeFile(filePath, content, "utf8");
}

async function beforeWrite(filePath: string, serial: string, dubID: string): Promise<string | null> {
  const result = await capture.beforeWrite({ serial, filePath, dubID }).catch(() => null);
  return result?.text ?? null;
}

async function afterWrite(filePath: string, serial: string): Promise<void> {
  await capture.afterWrite({ serial, filePath }).catch(() => null);
}

async function saveWrite(input: { dubID: string; serial: string; filePath: string; before: string | null; after: string; action: string }) {
  await capture.writeSnapshot(input as any);
}

// ── Text helpers ──────────────────────────────────────────────────────────────

function objectPayload(payload: unknown, action: string): Record<string, any> {
  if (payload && typeof payload === "object" && !Array.isArray(payload)) return payload as Record<string, any>;

  if (typeof payload === "string") {
    const clean = payload.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "");
    try {
      const parsed = JSON.parse(clean);
      if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed as Record<string, any>;
    } catch {}
  }

  throw new Error(`${action}_payload_must_be_object`);
}

type PayloadText = {
  value: string;
  notices: string[];
};

function deprecatedPayloadNotice(used: string, useInstead: string): string {
  return `Completed successfully using deprecated payload field "${used}". Please update future RecordingSheets to use "${useInstead}" instead.`;
}

function resultMessage(base: string, notices: string[] = []): string {
  return notices.length ? `${base}. ${notices.join(" ")}` : base;
}

function payloadInput(body: Record<string, any>, action: string, deprecatedAliases: string[] = []): PayloadText {
  if (typeof body.input === "string") return { value: body.input, notices: [] };

  for (const alias of deprecatedAliases) {
    if (typeof body[alias] === "string") {
      return { value: body[alias], notices: [deprecatedPayloadNotice(alias, "input")] };
    }
  }

  throw new Error(`${action}_input_missing`);
}

function payloadText(payload: unknown, action: string): PayloadText {
  if (typeof payload === "string") return { value: payload, notices: [] };
  const body = objectPayload(payload, action);
  return payloadInput(body, action);
}

function payloadRetain(body: Record<string, any>, action: string): PayloadText {
  if (typeof body.retain === "string") return { value: body.retain, notices: [] };
  if (typeof body.retained === "string") return { value: body.retained, notices: [deprecatedPayloadNotice("retained", "retain")] };
  throw new Error(`${action}_retain_missing`);
}
function countOccurrences(haystack: string, needle: string): number {
  if (!needle) return 0;
  let count = 0;
  let index = 0;
  while (true) {
    const found = haystack.indexOf(needle, index);
    if (found === -1) break;
    count++;
    index = found + needle.length;
  }
  return count;
}

function normalizeLines(text: string): { useCRLF: boolean; lines: string[] } {
  const useCRLF = text.includes("\r\n");
  return { useCRLF, lines: text.replace(/\r\n/g, "\n").split("\n") };
}

function joinLines(lines: string[], useCRLF: boolean): string {
  const text = lines.join("\n");
  return useCRLF ? text.replace(/\n/g, "\r\n") : text;
}

function replacementLines(value: string): string[] {
  const clean = value.replace(/\r\n/g, "\n").replace(/^\n+|\n+$/g, "");
  return clean ? clean.split("\n") : [];
}

function uniqueLineIndex(lines: string[], needle: string, errorPrefix: string): number {
  const cleanNeedle = String(needle || "").trim();
  if (!cleanNeedle) throw new Error(`${errorPrefix}_missing`);

  let matchIndex = -1;
  for (let i = 0; i < lines.length; i++) {
    if (lines[i].trim() !== cleanNeedle) continue;
    if (matchIndex !== -1) throw new Error(`${errorPrefix}_not_unique`);
    matchIndex = i;
  }

  if (matchIndex === -1) throw new Error(`${errorPrefix}_not_found`);
  return matchIndex;
}

function indentOf(line: string): string {
  return line.match(/^[ \t]*/)?.[0] ?? "";
}

function isTopLevelFunctionStartLine(line: string): boolean {
  if (!line.trim() || indentOf(line).length !== 0) return false;
  const t = line.trim();

  return (
    /^(export\s+)?(default\s+)?async\s+function\b/.test(t) ||
    /^(export\s+)?(default\s+)?function\b/.test(t) ||
    /^(export\s+)?(const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(async\s*)?\(/.test(t) ||
    /^(export\s+)?(const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(async\s*)?[A-Za-z_$][\w$]*\s*=>/.test(t) ||
    /^(export\s+)?[A-Za-z_$][\w$]*\s*\([^)]*\)\s*:\s*[^{=]+{?\s*$/.test(t) ||
    /^(export\s+)?[A-Za-z_$][\w$]*\s*\([^)]*\)\s*{?\s*$/.test(t)
  );
}

function nextTopLevelBoundary(lines: string[], startIndex: number): number {
  for (let i = startIndex + 1; i < lines.length; i++) {
    if (lines[i].trim() && isTopLevelFunctionStartLine(lines[i])) return i;
  }
  return lines.length;
}

// ── Shell Security Scanner ────────────────────────────────────────────────────

const DENIED_PATTERNS = [
  "..", "/", "C:\\",
  "&&", "|", ";", ">",
  "curl", "wget", "ssh",
  "sudo", "chmod", "iex",
  ".env", ".key", "id_rsa"
];

function getShellAccessMode(): "deny" | "standard" | "extended" {
  const mode = String(getSettings()?.recorder?.shellAccess || "deny").trim().toLowerCase();
  return mode === "standard" || mode === "extended" ? mode : "deny";
}

function scanShellCommand(command: string, args: string[]): { ok: boolean; reason?: string } {
  const mode = getShellAccessMode();
  if (mode === "deny") return { ok: false, reason: "access_denied_by_settings" };

  const cmd = command.toLowerCase();
  const joined = [cmd, ...args.map(arg => String(arg || "").toLowerCase())].join(" ");
  
  const aliasMap: Record<string, string> = { 
    'ren': 'rename', 'move': 'mv', 'copy': 'cp', 'del': 'rm' 
  };
  const normalizedCmd = aliasMap[cmd] || cmd;

  const isBlocked = DENIED_PATTERNS.some(pattern => joined.includes(pattern.toLowerCase()));
  if (isBlocked) return { ok: false, reason: "security_violation_banned_intent" };

  if (mode === "standard" && !["npm", "node", "python", "git", "mv", "cp", "rm", "rename"].includes(normalizedCmd)) {
    return { ok: false, reason: "command_not_in_standard_allowlist" };
  }

  return { ok: true };
}
// ── Apply actions ─────────────────────────────────────────────────────────────

async function applyNewFile(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const text = payloadText(payload, "newfile");

  try {
    await fs.access(filePath);
    throw new Error("newfile_target_already_exists");
  } catch (err: any) {
    if (err?.message === "newfile_target_already_exists") throw err;
  }

  await writeText(filePath, text.value);
  if (await readText(filePath) !== text.value) throw new Error("newfile_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before: null, after: text.value, action: "newfile" });
  capture.code({ action: "newfile", filePath, before: "", after: text.value, changed: true, outcome: "created" });

  return { ok: true, action: "newfile", filePath, changed: true, message: resultMessage("new file created", text.notices) };
}

async function applyRewriteFile(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const text = payloadText(payload, "rewritefile");

  const before = await readText(filePath).catch(() => { throw new Error("rewritefile_target_missing"); });
  await beforeWrite(filePath, serial, dubID);
  await capture.rewriteOriginal({ dubID, serial, filePath, content: before });

  await writeText(filePath, text.value);
  if (await readText(filePath) !== text.value) throw new Error("rewritefile_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after: text.value, action: "rewritefile" });
  capture.code({ action: "rewritefile", filePath, before, after: text.value, changed: true, outcome: "rewritten" });

  return { ok: true, action: "rewritefile", filePath, changed: true, message: resultMessage("file rewritten", text.notices) };
}

async function applyReplaceString(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, "replacestring");
  const target = typeof body.target === "string" ? body.target : null;
  const text = payloadInput(body, "replacestring", ["replacement"]);
  if (!target) throw new Error("replacestring_target_missing");

  const before = await readText(filePath);
  await beforeWrite(filePath, serial, dubID);
  if (!before.includes(target)) throw new Error("replacestring_target_not_found");

  const after = before.replace(target, text.value);
  if (after === before) throw new Error("replacestring_no_change");

  await writeText(filePath, after);
  if (await readText(filePath) !== after) throw new Error("replacestring_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after, action: "replacestring" });
  capture.code({ action: "replacestring", filePath, before, after, changed: true, outcome: "replaced" });

  return { ok: true, action: "replacestring", filePath, changed: true, message: resultMessage("string replaced", text.notices) };
}

async function applyReplaceAll(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, "replaceall");
  const target = typeof body.target === "string" ? body.target : null;
  const text = payloadInput(body, "replaceall", ["replacement"]);
  if (!target) throw new Error("replaceall_target_missing");

  const before = await readText(filePath);
  await beforeWrite(filePath, serial, dubID);
  const occurrences = countOccurrences(before, target);
  if (occurrences === 0) throw new Error("replaceall_target_not_found");

  const after = before.split(target).join(text.value);
  if (after === before) throw new Error("replaceall_no_change");

  await writeText(filePath, after);
  if (await readText(filePath) !== after) throw new Error("replaceall_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after, action: "replaceall" });
  capture.code({ action: "replaceall", filePath, before, after, changed: true, outcome: `replaced_${occurrences}` });

  return { ok: true, action: "replaceall", filePath, changed: true, message: resultMessage(`all occurrences replaced (${occurrences})`, text.notices) };
}

async function applyReplaceBlock(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, "replaceblock");
  const start = typeof body.start === "string" ? body.start : null;
  const retain = payloadRetain(body, "replaceblock");
  const text = payloadInput(body, "replaceblock", ["replacement"]);
  const notices = [...retain.notices, ...text.notices];

  if (!start) throw new Error("replaceblock_start_missing");

  const before = await readText(filePath);
  await beforeWrite(filePath, serial, dubID);
  
  const { useCRLF, lines } = normalizeLines(before);
  
  const startIndex = uniqueLineIndex(lines, start, "replaceblock_start");
  const retainIndex = uniqueLineIndex(lines, retain.value, "replaceblock_retain");
  
  if (retainIndex <= startIndex) throw new Error("replaceblock_retain_before_start");

  const after = joinLines([
    ...lines.slice(0, startIndex), 
    ...replacementLines(text.value), 
    ...lines.slice(retainIndex)
  ], useCRLF);

  if (after === before) throw new Error("replaceblock_no_change");

  await writeText(filePath, after);
  if (await readText(filePath) !== after) throw new Error("replaceblock_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after, action: "replaceblock" });
  capture.code({ action: "replaceblock", filePath, before, after, changed: true, outcome: "replaced" });

  return { ok: true, action: "replaceblock", filePath, changed: true, message: resultMessage("block replaced", notices) };
}

async function applyReplaceFunction(filePath: string, payload: unknown, dubID: string, serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, "replacefunction");
  const start = typeof body.start === "string" ? body.start : null;
  const text = payloadInput(body, "replacefunction", ["replacement"]);
  if (!start) throw new Error("replacefunction_start_missing");

  const before = await readText(filePath);
  await beforeWrite(filePath, serial, dubID);
  const { useCRLF, lines } = normalizeLines(before);
  const startIndex = uniqueLineIndex(lines, start, "replacefunction_start");
  if (!isTopLevelFunctionStartLine(lines[startIndex])) throw new Error("replacefunction_start_not_top_level");

  const boundary = nextTopLevelBoundary(lines, startIndex);
  if (boundary <= startIndex + 1) throw new Error("replacefunction_boundary_not_found");

  const after = joinLines([...lines.slice(0, startIndex), ...replacementLines(text.value), ...lines.slice(boundary)], useCRLF);
  if (after === before) throw new Error("replacefunction_no_change");

  await writeText(filePath, after);
  if (await readText(filePath) !== after) throw new Error("replacefunction_verification_failed");

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after, action: "replacefunction" });
  capture.code({ action: "replacefunction", filePath, before, after, changed: true, outcome: "replaced" });

  return { ok: true, action: "replacefunction", filePath, changed: true, message: resultMessage("top-level function replaced", text.notices) };
}

async function applyInsert(filePath: string, payload: unknown, actionName: "insertbefore" | "insertafter", dubID: string, serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, actionName);
  const find = typeof body.find === "string" ? body.find : null;
  const text = payloadInput(body, actionName, ["content"]);
  if (!find) throw new Error(`${actionName}_find_missing`);

  const before = await readText(filePath);
  await beforeWrite(filePath, serial, dubID);
  const hits = countOccurrences(before, find);
  if (hits === 0) throw new Error(`${actionName}_find_not_found`);
  if (hits > 1) throw new Error(`${actionName}_find_not_unique`);

  const idx = before.indexOf(find);
  const insertAt = actionName === "insertbefore" ? idx : idx + find.length;
  const after = before.slice(0, insertAt) + text.value + before.slice(insertAt);
  if (after === before) throw new Error(`${actionName}_no_change`);

  await writeText(filePath, after);
  if (await readText(filePath) !== after) throw new Error(`${actionName}_verification_failed`);

  await afterWrite(filePath, serial);
  await saveWrite({ dubID, serial, filePath, before, after, action: actionName });
  capture.code({ action: actionName, filePath, before, after, changed: true, outcome: "inserted" });

  return {
    ok: true,
    action: actionName,
    filePath,
    changed: true,
    message: resultMessage(actionName === "insertbefore" ? "content inserted before unique match" : "content inserted after unique match", text.notices)
  };
}

async function applyShell(filePath: string, payload: unknown, _dubID: string, _serial: string): Promise<RecorderResult> {
  const body = objectPayload(payload, "shell");
  const command = String(body.command || "").trim();
  const args = Array.isArray(body.args) ? body.args : [];
  if (!command) throw new Error("shell_command_missing");

  const scan = scanShellCommand(command, args);
  if (!scan.ok) throw new Error(`shell_${scan.reason}`);

  return new Promise((resolve, reject) => {
    const child = spawn(command, args, { cwd: resolveFile(filePath) });
    
    child.on("error", (err) => reject(new Error(`shell_spawn_failed_${err.message}`)));

    let output = "";
    child.stdout.on("data", (data) => output += data);
    child.stderr.on("data", (data) => output += data);
    
    child.on("close", (code) => {
      if (code === 0) resolve({ ok: true, action: "shell", filePath, changed: true, message: output.trim() });
      else reject(new Error(`shell_execution_failed_code_${code}`));
    });
  });
}

const applyAction: Record<RecorderAction, (filePath: string, payload: unknown, dubID: string, serial: string) => Promise<RecorderResult>> = {
  newfile: applyNewFile,
  rewritefile: applyRewriteFile,
  replaceblock: applyReplaceBlock,
  replacestring: applyReplaceString,
  replaceall: applyReplaceAll,
  replacefunction: applyReplaceFunction,
  insertbefore: (filePath, payload, dubID, serial) => applyInsert(filePath, payload, "insertbefore", dubID, serial),
  insertafter: (filePath, payload, dubID, serial) => applyInsert(filePath, payload, "insertafter", dubID, serial),
  shell: applyShell
};

// ── Failure classification / AI repair ───────────────────────────────────────

function classifyFailure(rawError: unknown): FailureClassification {
  const error = String(rawError ?? "").trim();
  const e = error.toLowerCase();

  if (e.includes("path_escape_blocked") || e.includes("path_outside") || e.includes("verification_failed") || e.includes("target_already_exists")) {
    return { lane: "OTHER", mode: "OTHER", rawError: error, normalizedReason: error || "not suitable for AI1 repair", repairEligible: false };
  }

  if (e.includes("filepath") || e.includes("file_not_found") || e.includes("enoent") || e.includes("no such file") || e.includes("rewritefile_target_missing")) {
    return { lane: "B", mode: "AI1B", rawError: error, normalizedReason: "file not found", repairEligible: true };
  }

  if (e.includes("unsupported_recorder_action") || e.includes("action_missing") || e.includes("payload_must_be_object") || e.includes("input_missing") || e.includes("replacement_missing") || e.includes("content_missing") || e.includes("start_missing") || e.includes("retain_missing") || e.includes("find_missing") || e.includes("newfile_payload_must_be_input") || e.includes("rewritefile_payload_must_be_input") || e.includes("newfile_payload_must_be_string") || e.includes("rewritefile_payload_must_be_string")) {
    return { lane: "C", mode: "AI1C", rawError: error, normalizedReason: "location not correctly defined", repairEligible: true };
  }

  if (e.includes("not_found") || e.includes("not_unique") || e.includes("retain_before_start") || e.includes("boundary_not_found") || e.includes("not_top_level") || e.includes("search_") || e.includes("find_") || e.includes("target_") || e.includes("start_") || e.includes("retain_")) {
    return { lane: "A", mode: "AI1A", rawError: error, normalizedReason: "string not found", repairEligible: true };
  }

  return { lane: "OTHER", mode: "OTHER", rawError: error, normalizedReason: error || "not suitable for AI1 repair", repairEligible: false };
}

function canAutoApplyRepair(original: RecorderManifest, adjusted: RecorderManifest, classification: FailureClassification): boolean {
  const origAction = normalizeAction(original.Action);
  const adjAction = normalizeAction(adjusted.Action);
  const origFile = String(original.FilePath || "").trim();
  const adjFile = String(adjusted.FilePath || "").trim();

  if (!adjAction || !RECORDER_ACTIONS.has(adjAction)) return false;
  if (classification.lane === "A") return origAction === adjAction && origFile === adjFile;
  if (classification.lane === "B") return origAction === adjAction && Boolean(adjFile);
  if (classification.lane === "C") return Boolean(adjAction);
  return false;
}

async function tryAIRepair(manifest: RecorderManifest, classification: FailureClassification, source: string): Promise<{ repaired: boolean; result?: RecorderResult; report?: any; error?: string }> {
  if (!classification.repairEligible) {
    capture.system({ tag: "Recorder", event: "aiRepair_no_safe_repair", source, lane: classification.lane, mode: classification.mode, reason: "repair_not_eligible" });
    return { repaired: false };
  }

  const fileText = await readTextMaybe(resolveFile(manifest.FilePath).replace(/\\/g, "/")).catch(() => null);
  capture.system({ tag: "Recorder", event: "aiRepair_call", source, lane: classification.lane, mode: classification.mode, FilePath: manifest.FilePath, Action: manifest.Action });

  const report = await investigateManifestFailure({
    manifest,
    error: classification.normalizedReason,
    rawError: classification.rawError,
    fileText,
    failureLane: classification.lane,
    failureMode: classification.mode,
    stage: "apply",
    repairAttempt: 0
  });

  const adjusted = (report?.adjustedManifest || report?.suggestedRepair?.manifest || null) as RecorderManifest | null;
  const confidence = Number(report?.confidence ?? 0);
  capture.system({ tag: "Recorder", event: "aiRepair_reply_received", source, lane: classification.lane, mode: classification.mode, confidence, status: report?.status || null });

  if (!adjusted || !canAutoApplyRepair(manifest, adjusted, classification) || confidence < 0.74) {
    capture.system({ tag: "Recorder", event: "aiRepair_no_safe_repair", source, lane: classification.lane, mode: classification.mode, confidence, hasAdjustedManifest: Boolean(adjusted) });
    return { repaired: false, report };
  }

  try {
    capture.system({ tag: "Recorder", event: "aiRepair_apply_start", source, lane: classification.lane, mode: classification.mode, originalFilePath: manifest.FilePath, adjustedFilePath: adjusted.FilePath, adjustedAction: adjusted.Action });
    const result = await record(adjusted);
    capture.system({ tag: "Recorder", event: "aiRepair_apply_success", source, lane: classification.lane, mode: classification.mode, FilePath: adjusted.FilePath });
    return { repaired: true, result, report };
  } catch (err: any) {
    const error = err?.message ?? String(err);
    capture.system({ tag: "Recorder", event: "aiRepair_apply_failure", source, lane: classification.lane, mode: classification.mode, error });
    return { repaired: false, report, error };
  }
}

// ── Execution ─────────────────────────────────────────────────────────────────

async function executeManifest(manifest: RecorderManifest, source: string): Promise<RunResult> {
  const dubID = `${Date.now()}${Math.random().toString(36).slice(2, 6)}`;

  capture.manifest("Recorder", "execute", manifest);
  capture.system({
    tag: "Recorder",
    event: "execute_start",
    dubID,
    source,
    Task: manifest?.Task ?? null,
    Action: manifest?.Action,
    FilePath: manifest?.FilePath
  });

  let targetAbs = "";
  try {
    targetAbs = resolveFile(String(manifest?.FilePath || ""));
  } catch (err: any) {
    const rawError = err?.message ?? String(err);
    const classification = classifyFailure(rawError);
    const status: "error" = "error";
    const result = {
      ok: false,
      error: classification.rawError,
      failureLane: classification.lane,
      failureMode: classification.mode,
      normalizedReason: classification.normalizedReason
    };

    capture.system({
      tag: "Recorder",
      event: "execute_error_surfaced",
      dubID,
      error: classification.rawError,
      lane: classification.lane,
      mode: classification.mode,
      Task: manifest?.Task ?? null,
      FilePath: manifest?.FilePath
    });

    await capture.tape.appendExecution({ dubID, status, manifest, result, source });
    return { dubID, manifest, status, result };
  }

  return await controller.withProjectForPath(targetAbs, async (projectContext) => {
    if (projectContext.switched) {
      capture.system({
        tag: "Recorder",
        event: "project_context_entered",
        serial: projectContext.serial,
        project: projectContext.name,
        FilePath: manifest?.FilePath
      });
    }

    let result: any = null;
    let status: "done" | "error" = "done";

    try {
      result = await record({ ...manifest, FilePath: targetAbs }, dubID);

      capture.system({
        tag: "Recorder",
        event: "execute_done",
        dubID,
        status: "done",
        Task: manifest?.Task ?? null,
        FilePath: manifest?.FilePath
      });
    } catch (err: any) {
      const classification = classifyFailure(err?.message ?? String(err));

      capture.system({
        tag: "Recorder",
        event: "execute_failure_detected",
        dubID,
        source,
        lane: classification.lane,
        mode: classification.mode,
        rawError: classification.rawError,
        normalizedReason: classification.normalizedReason,
        Task: manifest?.Task ?? null,
        FilePath: manifest?.FilePath
      });

      if (!recorderStatus.pauseRequested && classification.repairEligible) {
        const repair = await tryAIRepair(manifest, classification, source);

        if (repair.repaired) {
          status = "done";
          result = {
            ok: true,
            repaired: true,
            repairedFrom: classification.mode,
            originalError: classification.rawError,
            result: repair.result,
            eq: repair.report || undefined
          };

          capture.system({
            tag: "Recorder",
            event: "execute_done",
            dubID,
            status: "done",
            repairedFrom: classification.mode,
            Task: manifest?.Task ?? null,
            FilePath: manifest?.FilePath
          });
        }
      }

      if (!result) {
        status = "error";
        result = {
          ok: false,
          error: classification.rawError,
          failureLane: classification.lane,
          failureMode: classification.mode,
          normalizedReason: classification.normalizedReason
        };

        capture.system({
          tag: "Recorder",
          event: "execute_error_surfaced",
          dubID,
          error: classification.rawError,
          lane: classification.lane,
          mode: classification.mode,
          Task: manifest?.Task ?? null,
          FilePath: manifest?.FilePath
        });

        if (!recorderStatus.pauseRequested) {
          try {
            const failReport = await investigateManifestFailure({
              manifest,
              error: classification.normalizedReason,
              rawError: classification.rawError,
              failureLane: classification.lane,
              failureMode: classification.mode,
              stage: "apply",
              repairAttempt: 1
            });

            if (failReport) result.eq = failReport;
          } catch (eqErr: any) {
            capture.system({
              tag: "EQ",
              event: "assist_error",
              error: eqErr?.message ?? String(eqErr)
            });
          }
        }
      }
    }

    await capture.tape.appendExecution({ dubID, status, manifest, result, source });


    if (projectContext.switched) {
      capture.system({
        tag: "Recorder",
        event: "project_context_restored",
        serial: projectContext.serial,
        project: projectContext.name,
        FilePath: manifest?.FilePath
      });
    }

    return { dubID, manifest, status, result };
  });
}

async function executeInput(input: unknown, source: string): Promise<RunResult[]> {
  const manifests = scanManifestCandidates(input);
  if (!manifests.length) throw new Error("no_manifest_found");

  const results: RunResult[] = [];
  for (const manifest of manifests) {
    results.push(await executeManifest(manifest, source));
    if (recorderStatus.pauseRequested) break;
  }
  return results;
}

async function sweepNextApprovedTapeItem(): Promise<RunResult | null> {
  const tape = await capture.tape.load();
  const next = tape.find((item: any) => item.recorderStatus === "YES" && isManifestLike(item.manifest));
  if (!next) return null;

  await capture.tape.markRetrieved([next.dubID]);
  return await executeManifest(next.manifest as RecorderManifest, `tape:${next.source || "proposal"}`);
}

export async function wakeRecorder(input?: unknown, source = "direct"): Promise<any> {
  if (recorderStatus.paused) {
    if (input !== undefined) {
      pendingRuns.push({ input, source });
      capture.system({ tag: "Recorder", event: "queued_while_paused", source, queueLength: pendingRuns.length });
    }
    return { ok: true, ...currentStatus(), queued: pendingRuns.length > 0, message: "paused" };
  }

  if (recorderStatus.busy) {
    if (input !== undefined) {
      pendingRuns.push({ input, source });
      capture.system({ tag: "Recorder", event: "queued", source, queueLength: pendingRuns.length });
    }
    return { ok: true, ...currentStatus(), queued: pendingRuns.length > 0, message: "busy" };
  }

  recorderStatus.busy = true;
  capture.system({ tag: "Recorder", event: "active_on", source, ...currentStatus() });

  const runOne = async (jobInput?: unknown, jobSource = "direct"): Promise<any> => {
    const allResults: RunResult[] = [];

    if (jobInput !== undefined) {
      allResults.push(...await executeInput(jobInput, jobSource));
      if (recorderStatus.pauseRequested) engagePauseIfRequested("after_input");
    }

    while (!recorderStatus.paused && !recorderStatus.pauseRequested) {
      const tapeResult = await sweepNextApprovedTapeItem();
      if (!tapeResult) break;
      allResults.push(tapeResult);
      if (recorderStatus.pauseRequested) {
        engagePauseIfRequested("after_tape_item");
        break;
      }
    }

    if (!allResults.length) return { ok: true, message: "idle" };
    if (allResults.length === 1) {
      const first = allResults[0];
      return { ok: true, dubID: first.dubID, status: first.status, result: first.result };
    }

    return {
      ok: true,
      accepted: allResults.length,
      results: allResults.map(r => ({ dubID: r.dubID, status: r.status, action: r.manifest.Action, filePath: r.manifest.FilePath }))
    };
  };

  let response: any = { ok: true, message: "idle" };

  try {
    if (input !== undefined) response = await runOne(input, source);
    else if (pendingRuns.length > 0) {
      const next = pendingRuns.shift()!;
      capture.system({ tag: "Recorder", event: "dequeued", source: next.source, queueLength: pendingRuns.length });
      response = await runOne(next.input, next.source);
    } else response = await runOne(undefined, source);

    while (!recorderStatus.paused && !recorderStatus.pauseRequested && pendingRuns.length > 0) {
      const next = pendingRuns.shift()!;
      capture.system({ tag: "Recorder", event: "dequeued", source: next.source, queueLength: pendingRuns.length });
      await runOne(next.input, next.source);
    }

    if (recorderStatus.pauseRequested) engagePauseIfRequested("after_queue_item");
  } catch (err: any) {
    response = { ok: false, error: err?.message ?? String(err) };
  } finally {
    recorderStatus.busy = false;
    capture.system({ tag: "Recorder", event: "active_off", ...currentStatus() });
  }

  return { ...response, ...currentStatus(), queued: pendingRuns.length > 0 };
}

export async function record(manifest: RecorderManifest, dubID?: string): Promise<RecorderResult> {
  const validation = validateManifestShape(manifest, { requirePayload: true });
  if (!validation.ok) throw new Error(validation.error || "invalid_manifest");

  const action = normalizeAction(manifest.Action) as RecorderAction;
  if (!RECORDER_ACTIONS.has(action)) throw new Error(`unsupported_recorder_action:${action}`);

  const abs = resolveFile(manifest.FilePath);
  const id = dubID || capture.tape.nextDubID();
  return await applyAction[action](abs, manifest.Payload, id, controller.state().projectSerial || BACKSTAGE_SERIAL);
}