import { readFileSync, readdirSync } from "fs";
import path from "path";

import { sql } from "drizzle-orm";
import { afterAll, beforeEach, vi } from "vitest";

import * as schema from "@/lib/db/schema";

/**
 * Integration database wiring (Drizzle).
 *
 *  - If TEST_DATABASE_URL is set, the real `@/lib/db` singleton is used unchanged,
 *    pointed at that Postgres. Migrations are applied once by the global setup;
 *    files run serially and truncate between tests.
 *
 *  - Otherwise, `@/lib/db` is mocked with a Drizzle client backed by an in-process
 *    PGlite database (Postgres compiled to WASM) — real Postgres semantics, fully
 *    isolated per worker, no external server. Production code is never modified.
 */

const realDbUrl = process.env.TEST_DATABASE_URL?.trim();
if (realDbUrl) {
  process.env.DATABASE_URL = realDbUrl;
}

vi.mock("@/lib/db", async () => {
  if (process.env.TEST_DATABASE_URL?.trim()) {
    return await vi.importActual<typeof import("@/lib/db")>("@/lib/db");
  }

  const { PGlite } = await import("@electric-sql/pglite");
  const { drizzle } = await import("drizzle-orm/pglite");

  const client = new PGlite();
  const migrationsDir = path.resolve(process.cwd(), "lib", "db", "migrations");
  const files = readdirSync(migrationsDir)
    .filter((entry) => entry.endsWith(".sql"))
    .sort();
  for (const file of files) {
    await client.exec(readFileSync(path.join(migrationsDir, file), "utf8"));
  }

  const db = drizzle(client, { schema });
  return { db, schema };
});

const { db } = await import("@/lib/db");

export { db };

// Truncated in dependency order (children first) between every test for isolation.
const TABLES = [
  "media_usage",
  "media_asset",
  "portfolio_asset",
  "portfolio_section",
  "portfolio_project",
  "category",
  "app_config",
];

export async function resetDb() {
  const list = TABLES.map((table) => `"${table}"`).join(", ");
  await db.execute(sql.raw(`TRUNCATE TABLE ${list} RESTART IDENTITY CASCADE;`));
}

beforeEach(async () => {
  await resetDb();
});

afterAll(async () => {
  // PGlite is in-process and torn down with the worker; the real postgres.js
  // client is a shared singleton and is left open on purpose.
});
