// sysutil/consolidate-tapedeck-current.ts
// scope: one-time consolidation of legacy per-project TapeDeck files into tape-current.jsonl

import path from "node:path";
import { promises as fs } from "node:fs";
import { DataPaths } from "../pathList";

type TapeItem = {
  dubID?: string;
  status?: string;
  recorderStatus?: string;
  kind?: string;
  source?: string;
  project?: string;
  projectSerial?: string;
  manifest?: any;
  result?: any;
  timestamp?: number;
  [key: string]: any;
};

function tapeCurrentFile(): string { return path.join(DataPaths.logsDir, "tape-current.jsonl"); }
function rowKey(item: TapeItem): string {
  return [item.dubID || "", item.status || "", item.timestamp || "", item.projectSerial || ""].join("|");
}
async function readJsonValue<T>(filePath: string, fallback: T): Promise<T> {
  try {
    const raw = await fs.readFile(filePath, "utf8");
    return raw.trim() ? JSON.parse(raw) as T : fallback;
  } catch { return fallback; }
}
async function readTapeCurrent(): Promise<TapeItem[]> {
  let raw = "";
  try { raw = await fs.readFile(tapeCurrentFile(), "utf8"); }
  catch { return []; }
  return raw.split("\n")
    .filter(Boolean)
    .map(line => { try { return JSON.parse(line) as TapeItem; } catch { return null; } })
    .filter((item): item is TapeItem => Boolean(item?.dubID));
}
async function writeTapeCurrent(items: TapeItem[]): Promise<void> {
  await fs.mkdir(path.dirname(tapeCurrentFile()), { recursive: true });
  await fs.writeFile(tapeCurrentFile(), items.map(item => JSON.stringify(item)).join("\n") + (items.length ? "\n" : ""), "utf8");
}
type LegacyTapeFile = { serial: string; filePath: string };

function serialFromTapePath(filePath: string): string {
  const parent = path.basename(path.dirname(filePath));
  return String(parent || "legacy").trim() || "legacy";
}

async function discoverLegacyTapeFiles(root = DataPaths.logsDir): Promise<LegacyTapeFile[]> {
  const found: LegacyTapeFile[] = [];
  async function walk(dir: string): Promise<void> {
    let entries: import("node:fs").Dirent[] = [];
    try { entries = await fs.readdir(dir, { withFileTypes: true }); }
    catch { return; }

    for (const entry of entries) {
      const full = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        if (entry.name === "archive" || entry.name === "system" || entry.name === "scrapes") continue;
        await walk(full);
        continue;
      }
      if (!entry.isFile() || entry.name !== "tape.json") continue;
      found.push({ serial: serialFromTapePath(full), filePath: full });
    }
  }

  await walk(root);
  return found.sort((a, b) => a.filePath.localeCompare(b.filePath));
}
async function main(): Promise<void> {
  const current = await readTapeCurrent();
  const seen = new Set(current.map(rowKey));
  const legacyFiles = await discoverLegacyTapeFiles();
  let added = 0;
  const bySerial: Record<string, number> = {};

  for (const legacyFile of legacyFiles) {
    const serial = legacyFile.serial;
    const legacy = await readJsonValue<TapeItem[]>(legacyFile.filePath, []);
    for (const item of legacy) {
      if (!item?.dubID) continue;
      const normalized = { ...item, projectSerial: String(item.projectSerial || serial).trim() || serial };
      const key = rowKey(normalized);
      if (seen.has(key)) continue;
      current.push(normalized);
      seen.add(key);
      bySerial[serial] = (bySerial[serial] || 0) + 1;
      added++;
    }
  }

  current.sort((a, b) => Number(a.timestamp || 0) - Number(b.timestamp || 0));
  if (added > 0) await writeTapeCurrent(current);
  console.log(JSON.stringify({ ok: true, scannedFiles: legacyFiles.length, added, total: current.length, bySerial }, null, 2));
}