import { drizzle, type NodePgDatabase } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";

/**
 * One pool per process, built on first use.
 *
 * Lazily, not at import, for two reasons. `next build` evaluates every route
 * module to collect its configuration, and a pool built there would either
 * demand a DATABASE_URL on the build machine — which has no database and should
 * need no secrets — or swallow the check and fail much later. And Next's dev
 * server re-evaluates modules on every edit, so without the global the pool
 * would be rebuilt until Postgres refused the hundredth connection.
 */
const globalForDb = globalThis as unknown as { pool?: Pool };

let built: Pool | null = null;

function realPool(): Pool {
  if (built) return built;
  if (globalForDb.pool) return (built = globalForDb.pool);

  const url = process.env.DATABASE_URL;
  if (!url) {
    // Failing here beats failing on the first query with a driver error that
    // says nothing about which of the seven variables was forgotten.
    throw new Error("DATABASE_URL is not set — see .env.example");
  }
  built = new Pool({
    connectionString: url,
    // The dashboard needs a handful; the worker runs ten audits at a time and
    // touches the database only at the start and the end of each.
    max: Number(process.env.PGPOOL_MAX ?? 10),
  });
  if (process.env.NODE_ENV !== "production") globalForDb.pool = built;
  return built;
}

/** Forward every access to the real object, building it on the first one. */
function lazy<T extends object>(build: () => T): T {
  return new Proxy({} as T, {
    get(_target, property) {
      const instance = build();
      const value = Reflect.get(instance, property, instance);
      return typeof value === "function" ? value.bind(instance) : value;
    },
  });
}

export const pool: Pool = lazy(realPool);

// `drizzle()` inspects its client as it is constructed, so it too has to wait
// until something actually queries.
let database: NodePgDatabase<typeof schema> | null = null;

export const db: NodePgDatabase<typeof schema> = lazy(
  () => (database ??= drizzle(realPool(), { schema })),
);

export * from "./schema";
