// capture.ts
// Scope: recording what happened.
// Central landing module for logs, code diffs, tape execution records, manual restore points,
// auto-backup notes, hash updates, and future scrapes.
// Current version wraps existing playback/recovery/hashState owners while they are being reduced.

import path from "node:path";
import { promises as fs } from "node:fs";
import {
  logSystem,
  logAI,
  logCode,
  logManifestFull,
  readLog,
  clearLog,
  queueProposalToTape,
  appendExecutionToTape,
  approveManifestOnTape,
  loadTape,
  loadDubsTape,
  setDubsClearAfter,
  clearTapeItems,
  markTapeItemsRetrieved,
  nextDubID
} from "./playbackCore";
import {
  noteSuccessfulRecorderRun,
  saveWriteSnapshot,
  saveRewriteOriginal,
  createRestorePoint,
  listRestorePoints,
  restoreFromPoint,
  captureFileTree,
  captureScrape
} from "./restoreCore";
import {
  detectExternalDrift,
  summarizeFileState,
  updateKnownFileHash
} from "./hashState";
import { ROOT, RuntimePaths, DataPaths } from "./pathList";

export type CaptureEvent = {
  tag?: string;
  event: string;
  [key: string]: any;
};

export const capture = {
  system(input: CaptureEvent): void {
    const { tag = "System", ...payload } = input;
    logSystem(tag, payload);
  },

  manifest(tag: string, event: string, payload: unknown): void {
    logManifestFull(tag, event, payload);
  },

  ai(...args: any[]): void {
    (logAI as any)(...args);
  },

  code(input: Parameters<typeof logCode>[0]): void {
    logCode(input);
  },

  async readLog(stream: Parameters<typeof readLog>[0], limit?: number) {
    return await readLog(stream, limit);
  },

  async clearLog(stream: Parameters<typeof clearLog>[0]) {
    return await clearLog(stream);
  },

  async beforeWrite(input: { serial: string; filePath: string; dubID: string }) {
    const abs = path.resolve(input.filePath);
    const rel = path.relative(ROOT, abs).replace(/\\/g, "/");
    const text = await fs.readFile(abs, "utf8").catch(() => null);
    if (text === null) return { ok: true, exists: false, text: null };

    const drift = await detectExternalDrift(input.serial, rel).catch(() => null);
    if (drift?.drifted) {
      logSystem("Capture", {
        event: "external_drift_detected",
        dubID: input.dubID,
        filePath: input.filePath,
        knownHash: drift.knownHash,
        currentHash: drift.currentHash
      });
    }

    return { ok: true, exists: true, text, drift };
  },

  async afterWrite(input: { serial: string; filePath: string }) {
    const abs = path.resolve(input.filePath);
    const rel = path.relative(ROOT, abs).replace(/\\/g, "/");
    const summary = await summarizeFileState(abs);
    await updateKnownFileHash(input.serial, rel, summary);
    return { ok: true, summary };
  },

  async writeSnapshot(input: Parameters<typeof saveWriteSnapshot>[0]) {
    return await saveWriteSnapshot(input);
  },

  async rewriteOriginal(input: Parameters<typeof saveRewriteOriginal>[0]) {
    return await saveRewriteOriginal(input);
  },

  async successfulRecorderRun(input: Parameters<typeof noteSuccessfulRecorderRun>[0]) {
    return await noteSuccessfulRecorderRun(input);
  },

  tree: captureFileTree,
  scrape: captureScrape,

  tape: {
    nextDubID,
    queueProposal: queueProposalToTape,
    appendExecution: appendExecutionToTape,
    approveManifest: approveManifestOnTape,
    load: loadTape,
    loadDubs: loadDubsTape,
    clearDubs: setDubsClearAfter,
    clearItems: clearTapeItems,
    markRetrieved: markTapeItemsRetrieved
  },

  restorePoints: {
    create: createRestorePoint,
    list: listRestorePoints,
    apply: restoreFromPoint
  },

  paths: {
    root: ROOT,
    temp: RuntimePaths.tempDir,
    logs: DataPaths.logsDir,
    scrapes: DataPaths.scrapesDir
  }
};

export const logCaptureSystem = capture.system;
export const logCaptureCode = capture.code;
export const logCaptureManifest = capture.manifest;
export const readCaptureLog = capture.readLog;
export const clearCaptureLog = capture.clearLog;
export const captureBeforeWrite = capture.beforeWrite;
export const captureAfterWrite = capture.afterWrite;
export const saveCaptureWriteSnapshot = capture.writeSnapshot;
export const saveCaptureRewriteOriginal = capture.rewriteOriginal;
export const noteCaptureSuccessfulRecorderRun = capture.successfulRecorderRun;
export const captureTree = capture.tree;
export const captureScrapeSnapshot = capture.scrape;

