import crypto from "crypto";
import fs from "fs";
import path from "path";
import { resolveServiceCwd } from "../config/index.mjs";

const LOCAL_IMAGE = "pgvector/pgvector:pg16";
const LOCAL_USER = "testkit";

export async function computeTemplateFingerprint(config) {
  const hash = crypto.createHash("sha256");
  const db = config.testkit.database;
  hash.update(JSON.stringify({
    provider: db.provider,
    selectedBackend: db.selectedBackend,
    image: db.image || LOCAL_IMAGE,
    user: db.user || LOCAL_USER,
    migrate: config.testkit.migrate || null,
    seed: config.testkit.seed || null,
  }));

  for (const envFile of config.testkit.envFiles || []) {
    appendFileToHash(hash, config.productDir, resolveServiceCwd(config.productDir, envFile));
  }
  for (const input of db.template.inputs || []) {
    appendInputToHash(hash, config.productDir, input);
  }

  return hash.digest("hex");
}

export function appendInputToHash(hash, productDir, input) {
  const absPath = resolveServiceCwd(productDir, input);
  if (!fs.existsSync(absPath)) {
    hash.update(`missing:${path.relative(productDir, absPath)}`);
    return;
  }

  const stat = fs.statSync(absPath);
  if (stat.isDirectory()) {
    hash.update(`dir:${path.relative(productDir, absPath)}`);
    for (const entry of fs.readdirSync(absPath).sort()) {
      if (entry === ".git" || entry === "node_modules" || entry === ".testkit") continue;
      appendInputToHash(hash, productDir, path.join(input, entry));
    }
    return;
  }

  appendFileToHash(hash, productDir, absPath);
}

export function appendFileToHash(hash, productDir, absPath) {
  if (!fs.existsSync(absPath)) {
    hash.update(`missing:${path.relative(productDir, absPath)}`);
    return;
  }
  const stat = fs.statSync(absPath);
  if (!stat.isFile()) return;

  hash.update(`file:${path.relative(productDir, absPath)}:${stat.size}:${stat.mtimeMs}`);
  hash.update(fs.readFileSync(absPath));
}
