// src/lib/db/assert-test-db.ts
// Safety guards for destructive DB scripts/tests.
// Call the relevant assert*() BEFORE any db.delete()/truncate: it refuses to
// run unless the live connection points at an expected database name. This
// prevents a wipe of the dev/prod DB when DATABASE_URL is exported in the
// environment (which takes precedence over .env(.test) in Bun).
import { sql } from "drizzle-orm";
import { db } from "./client";

async function currentDatabaseName(): Promise<string> {
  const rows = (await db.execute(
    sql`select current_database() as name`,
  )) as unknown as Array<{ name: string }>;
  return rows[0]?.name ?? "";
}

// Exactly `seo_insight_test` (matches db:migrate:test / the `test` script), or
// that name with a strict `_<suffix>` (e.g. per-worker/CI DBs like
// `seo_insight_test_ci`). A bare `/_test$/` was too permissive — it would
// happily accept "seo_insight_test" but also any unrelated "*_test" database,
// including a mistyped prod-adjacent name.
const TEST_DB_NAME_RE = /^seo_insight_test(_[a-z0-9]+)?$/;

export function isTestDbName(name: string): boolean {
  return TEST_DB_NAME_RE.test(name);
}

/** Guard for DB integration tests (`DB_TESTS=1`): refuses anything but the
 *  test DB, in particular the dev DB the test runner would otherwise wipe if
 *  DATABASE_URL leaks from the environment. Used across ~40 *.test.ts files —
 *  do not widen this to accept `seo_insight_dev`. */
export async function assertTestDb(): Promise<void> {
  const name = await currentDatabaseName();
  if (!isTestDbName(name)) {
    throw new Error(
      `assertTestDb: refusing to run destructive DB tests against "${name || "unknown"}" — ` +
        "point DATABASE_URL at seo_insight_test (or a seo_insight_test_<suffix> DB) first.",
    );
  }
}

// seed.ts is documented (SETUP.md) to run against BOTH the dev DB (`bun run
// db:seed`, plain `.env`) and the test DB (`DATABASE_URL=...seo_insight_test
// bun run src/lib/db/seed.ts`) — unlike assertTestDb() above, it must not
// reject `seo_insight_dev`. It still guards against the actual SEC-P4 risk: a
// leaked/wrong DATABASE_URL (e.g. pointed at prod) making `seed.ts` wipe data
// it has no business touching.
const SEEDABLE_DB_NAME_RE = /^seo_insight_(dev|test(_[a-z0-9]+)?)$/;

export function isSeedableDbName(name: string): boolean {
  return SEEDABLE_DB_NAME_RE.test(name);
}

/** Guard for `seed.ts`: refuses to run unless DATABASE_URL resolves to a known
 *  local dev/test database. See isSeedableDbName's comment for why this is
 *  intentionally broader than assertTestDb(). */
export async function assertSeedableDb(): Promise<void> {
  const name = await currentDatabaseName();
  if (!isSeedableDbName(name)) {
    throw new Error(
      `assertSeedableDb: refusing to seed "${name || "unknown"}" — ` +
        "point DATABASE_URL at seo_insight_dev or seo_insight_test first.",
    );
  }
}
