#!/usr/bin/env node
/**
 * export-dev-seed.mjs
 *
 * Dumps the current dev database into packages/db/prisma/dev-seed.sql.
 * The dump is safe to commit: passwords, TOTP secrets, SMTP credentials,
 * and webhook secrets are all sanitized before writing.
 *
 * Usage:
 *   node scripts/export-dev-seed.mjs
 *
 * Requirements:
 *   - The capakraken-postgres-1 Docker container must be running
 *   - DATABASE_URL must point to a local capakraken database
 */

import { execSync, spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { loadWorkspaceEnv, resolveRealWorkspaceRoot } from "./load-env.mjs";

loadWorkspaceEnv();
const workspaceRoot = resolveRealWorkspaceRoot();

// ── Safety check ─────────────────────────────────────────────────────────────

const rawUrl = process.env["DATABASE_URL"];
if (!rawUrl) {
  console.error("❌  DATABASE_URL is not set.");
  process.exit(1);
}

let parsedUrl;
try {
  parsedUrl = new URL(rawUrl);
} catch {
  console.error("❌  DATABASE_URL is not a valid URL.");
  process.exit(1);
}

const host = parsedUrl.hostname;
if (!["localhost", "127.0.0.1", "::1"].includes(host)) {
  console.error(`❌  Refusing to export from non-local host: ${host}`);
  console.error("    export-dev-seed is only for local development databases.");
  process.exit(1);
}

// ── Docker container check ────────────────────────────────────────────────────

const CONTAINER = "capakraken-postgres-1";
const containerCheck = spawnSync("docker", ["inspect", "--format={{.State.Running}}", CONTAINER], {
  encoding: "utf8",
});
if (containerCheck.stdout.trim() !== "true") {
  console.error(`❌  Container ${CONTAINER} is not running.`);
  console.error("    Start it with: docker compose up -d postgres");
  process.exit(1);
}

// ── Tables to exclude entirely ────────────────────────────────────────────────

const EXCLUDE_TABLES = [
  "_prisma_migrations",
  "audit_logs",
  "active_sessions",
  "sessions",
  "accounts",
  "verification_tokens",
  "invite_tokens",
  "notifications",
  "import_batches",
  "staged_assignments",
  "staged_availability_rules",
  "staged_clients",
  "staged_projects",
  "staged_resources",
  "staged_unresolved_records",
  "staged_vacations",
];

const excludeFlags = EXCLUDE_TABLES.flatMap((t) => ["--exclude-table-data", `public.${t}`]);

// ── Run pg_dump inside the Docker container ───────────────────────────────────

const DB_USER = decodeURIComponent(parsedUrl.username) || "capakraken";
const DB_NAME = parsedUrl.pathname.replace(/^\/+/, "") || "capakraken";
const DB_PORT = parsedUrl.port || "5432";

console.log(`🔍  Exporting ${DB_USER}@${host}:${DB_PORT}/${DB_NAME} …`);

const pgDumpArgs = [
  "exec",
  CONTAINER,
  "pg_dump",
  "-U", DB_USER,
  "-d", DB_NAME,
  "--data-only",
  "--no-owner",
  "--no-acl",
  "--disable-triggers",
  ...excludeFlags,
];

const dump = spawnSync("docker", pgDumpArgs, { encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });

if (dump.status !== 0) {
  console.error("❌  pg_dump failed:");
  console.error(dump.stderr);
  process.exit(1);
}

// ── Sanitize sensitive values ─────────────────────────────────────────────────

let sql = dump.stdout;

// Replace argon2id password hashes with a clearly invalid placeholder.
// The import script will update these with a real dev hash.
sql = sql.replace(/\$argon2id\$[^\t\n\\]*/g, "__DEV_PASSWORD_HASH__");

// Append sanitizing statements (TOTP, SMTP password, webhook secrets).
// These run after the COPY blocks so they don't require line-level parsing.
sql += `
-- ─── Sanitize secrets (applied after data load) ──────────────────────────────
UPDATE users SET "totpSecret" = NULL, "totpEnabled" = false;
UPDATE system_settings SET "smtpPassword" = NULL;
UPDATE webhooks SET secret = NULL;
`;

// ── Add header ────────────────────────────────────────────────────────────────

const header = `-- CapaKraken dev seed — exported ${new Date().toISOString()}
-- Source: ${DB_USER}@${host}:${DB_PORT}/${DB_NAME}
--
-- Excluded tables:
${EXCLUDE_TABLES.map((t) => `--   ${t}`).join("\n")}
--
-- Sanitized fields:
--   users.passwordHash     → placeholder (import-dev-seed sets "Dev123456!")
--   users.totpSecret       → NULL
--   users.totpEnabled      → false
--   system_settings.smtpPassword → NULL
--   webhooks.secret        → NULL
--
-- Import with:
--   node scripts/import-dev-seed.mjs
-- ─────────────────────────────────────────────────────────────────────────────

`;

// ── Write output ──────────────────────────────────────────────────────────────

const outPath = resolve(workspaceRoot, "packages/db/prisma/dev-seed.sql");
writeFileSync(outPath, header + sql, "utf8");

const lines = (header + sql).split("\n").length;
const sizeKb = Math.round(Buffer.byteLength(header + sql, "utf8") / 1024);
console.log(`✅  Written to packages/db/prisma/dev-seed.sql`);
console.log(`    ${lines.toLocaleString()} lines · ${sizeKb.toLocaleString()} KB`);
console.log();
console.log("Next step: commit dev-seed.sql or share it with your team.");
console.log("Import it with:  node scripts/import-dev-seed.mjs");
