import { readdirSync, readFileSync, statSync } from "node:fs";
import { basename, join } from "node:path";
import { deployDir, incidentAssetsDir } from "../paths";
import type { BriefDeps, KbSummary } from "./dispatch-brief";

function readTextOrNull(path: string): string | null {
  try {
    return readFileSync(path, "utf8");
  } catch {
    return null;
  }
}

function kbFrontmatter(raw: string): Record<string, string> {
  const match = /^---\n([\s\S]*?)\n---/.exec(raw);
  if (!match) return {};
  const fields: Record<string, string> = {};
  for (const line of match[1]!.split("\n")) {
    const separator = line.indexOf(":");
    if (separator === -1) continue;
    fields[line.slice(0, separator).trim()] = line.slice(separator + 1).trim();
  }
  return fields;
}

function kbBodyLines(raw: string): { whatHappened: string; howSolved: string } {
  const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, "");
  const lines = body.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
  return { whatHappened: lines[0] ?? "", howSolved: lines[1] ?? "" };
}

export function createDeployAssetDeps(assetsDir: string = incidentAssetsDir()): BriefDeps {
  return {
    readAsset(name: string): string | null {
      if (name !== basename(name)) return null;
      return readTextOrNull(join(assetsDir, name));
    },
    listKb(): KbSummary[] {
      let files: string[];
      try {
        files = readdirSync(join(assetsDir, "kb")).filter((file) => file.endsWith(".md"));
      } catch {
        return [];
      }
      const entries: KbSummary[] = [];
      for (const file of files) {
        const raw = readTextOrNull(join(assetsDir, "kb", file));
        if (raw === null) continue;
        const front = kbFrontmatter(raw);
        const { whatHappened, howSolved } = kbBodyLines(raw);
        entries.push({
          id: front["id"] ?? file.replace(/\.md$/, ""),
          type: front["type"] ?? "",
          whatHappened,
          howSolved,
        });
      }
      return entries.sort((a, b) => b.id.localeCompare(a.id));
    },
    skillExists(name: string): boolean {
      if (name !== basename(name) || name.length === 0) return false;
      try {
        return statSync(join(assetsDir, "..", "skills", name, "SKILL.md")).isFile();
      } catch {
        return false;
      }
    },
  };
}

function resolveGitHead(gitDir: string): string | null {
  const head = readTextOrNull(join(gitDir, "HEAD"))?.trim();
  if (!head) return null;
  if (/^[0-9a-f]{40}$/.test(head)) return head;
  const ref = /^ref: (.+)$/.exec(head)?.[1];
  if (!ref) return null;
  const direct = readTextOrNull(join(gitDir, ref))?.trim();
  if (direct && /^[0-9a-f]{40}$/.test(direct)) return direct;
  const packed = readTextOrNull(join(gitDir, "packed-refs"));
  if (!packed) return null;
  for (const line of packed.split("\n")) {
    const [sha, name] = line.split(" ");
    if (name === ref && sha && /^[0-9a-f]{40}$/.test(sha)) return sha;
  }
  return null;
}

export function readDeployProvenance(deployRoot: string = deployDir()): string {
  const gitDir = join(deployRoot, ".git");
  const sha = resolveGitHead(gitDir);
  let stampedAt: string | null = null;
  try {
    stampedAt = statSync(join(gitDir, "HEAD")).mtime.toISOString();
  } catch {
    stampedAt = null;
  }
  return JSON.stringify({ sha: sha ?? "unknown", stampedAt, assetsRoot: deployRoot });
}
