/**
 * Prisma Schema Safety Check
 * ───────────────────────────
 * Runs before `prisma db push` in the build pipeline.
 * Aborts the build if the pending schema diff contains any destructive
 * operations: DROP COLUMN, DROP TABLE, DROP CONSTRAINT, DROP INDEX,
 * or ALTER COLUMN ... DROP.
 *
 * DROP INDEX is included because db push silently drops any index that
 * is not declared in schema.prisma, even if it is a large production
 * index (e.g. SiteEvent_sessionId_timestamp_idx on the ~22GB SiteEvent
 * table). Losing such an index causes full table scans on hot queries.
 *
 * Override: set ALLOW_SCHEMA_DROPS=true in the build environment to skip.
 */

import { execSync } from "child_process";

const DATABASE_URL = process.env.DATABASE_URL;

if (!DATABASE_URL) {
  console.log("[prisma-safety] DATABASE_URL not set — skipping safety check");
  process.exit(0);
}

if (process.env.ALLOW_SCHEMA_DROPS === "true") {
  console.log("[prisma-safety] ALLOW_SCHEMA_DROPS=true — skipping drop check");
  process.exit(0);
}

console.log("[prisma-safety] Computing schema diff against live database...");

// Retry up to 3 times to handle transient P1001 connection errors on cold starts.
const MAX_RETRIES = 3;
let diffSql;
let lastErr;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
  try {
    diffSql = execSync(
      "npx prisma migrate diff --from-url $DATABASE_URL --to-schema-datamodel prisma/schema.prisma --script",
      { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] },
    );
    lastErr = null;
    break;
  } catch (err) {
    lastErr = err;
    const stderr = err.stderr ?? "";
    const isTransient =
      stderr.includes("P1001") ||
      stderr.includes("Could not connect") ||
      stderr.includes("connection");
    if (isTransient && attempt < MAX_RETRIES) {
      console.warn(`[prisma-safety] Connection attempt ${attempt} failed — retrying...`);
      // brief pause before retry (synchronous busy-wait, safe in build context)
      const wait = attempt * 2000;
      const end = Date.now() + wait;
      while (Date.now() < end) { /* spin */ }
      continue;
    }
    if (isTransient) {
      console.warn("[prisma-safety] Could not connect to database after retries — skipping safety check");
      console.warn("[prisma-safety]", stderr.split("\n")[0]);
      process.exit(0);
    }
    console.error("[prisma-safety] Failed to compute schema diff:");
    console.error(stderr || err.message);
    process.exit(1);
  }
}
if (lastErr) {
  // Should not reach here, but guard anyway.
  console.warn("[prisma-safety] Exhausted retries — skipping safety check");
  process.exit(0);
}

// Patterns that signal data-destructive or performance-destructive operations.
// DROP INDEX is included: db push silently drops undeclared indexes, turning
// hot queries into full table scans (root cause of the SiteEvent incident).
const DROP_PATTERNS = [
  /^\s*ALTER TABLE\s+\S+\s+DROP COLUMN\s+/im,
  /^\s*DROP TABLE\s+/im,
  /^\s*DROP CONSTRAINT\s+/im,
  /^\s*ALTER TABLE\s+\S+\s+DROP CONSTRAINT\s+/im,
  /^\s*ALTER COLUMN\s+\S+\s+DROP\s+/im,
  /^\s*DROP INDEX\s+/im,
];

const matchedStatements = DROP_PATTERNS
  .flatMap((pattern) => {
    const lines = diffSql.split("\n");
    return lines.filter((line) => pattern.test(line));
  })
  .filter((line, i, arr) => arr.indexOf(line) === i); // deduplicate

if (matchedStatements.length > 0) {
  console.error("");
  console.error("╔══════════════════════════════════════════════════════════════╗");
  console.error("║  PRISMA SAFETY CHECK FAILED — BUILD ABORTED                 ║");
  console.error("╠══════════════════════════════════════════════════════════════╣");
  console.error("║  The schema diff would execute the following destructive     ║");
  console.error("║  SQL statements that could permanently delete production     ║");
  console.error("║  data or drop production indexes (causing full table scans): ║");
  console.error("╚══════════════════════════════════════════════════════════════╝");
  console.error("");
  matchedStatements.forEach((stmt) => console.error("  ⚠", stmt.trim()));
  console.error("");
  console.error("  Full diff SQL:");
  console.error("  " + diffSql.split("\n").join("\n  "));
  console.error("");
  console.error("  If this drop is intentional, set  ALLOW_SCHEMA_DROPS=true");
  console.error("  in the Vercel build environment and redeploy.");
  console.error("");
  process.exit(1);
}

console.log("[prisma-safety] No destructive operations found. Build can proceed.");
process.exit(0);
