/**
 * Schema-drift detection (T6).
 *
 * The cPanel/Passenger host boots server.js directly and runs NO migrations
 * (only ./deploy.sh does). A bare `git pull` + restart can therefore serve new
 * code against an old schema — the failure mode behind the 2026-05-31 login
 * outage. deploy.sh closes the happy path; this detects the bypass at runtime
 * so the operator gets loud, immediate evidence instead of silent AccessDenied
 * / "Unknown column" errors.
 */
import { existsSync, readdirSync } from 'fs';
import path from 'path';
import { prisma } from '@/lib/prisma';

const MIGRATIONS_DIR = path.resolve(process.cwd(), 'prisma', 'migrations');

/** Pure diff: on-disk migration names that are not in the applied set. */
export function pendingMigrationNames(onDisk: string[], applied: string[]): string[] {
    const appliedSet = new Set(applied);
    return onDisk.filter((name) => !appliedSet.has(name));
}

/** Migration directory names on disk (each subdir is one migration), sorted. */
export function readOnDiskMigrations(dir: string = MIGRATIONS_DIR): string[] {
    if (!existsSync(dir)) return [];
    return readdirSync(dir, { withFileTypes: true })
        .filter((entry) => entry.isDirectory())
        .map((entry) => entry.name)
        .sort();
}

/** Names of migrations recorded as finished in Prisma's bookkeeping table. */
export async function getAppliedMigrations(): Promise<string[]> {
    const rows = await prisma.$queryRaw<{ migration_name: string }[]>`
        SELECT migration_name FROM _prisma_migrations WHERE finished_at IS NOT NULL
    `;
    return rows.map((r) => r.migration_name);
}

/** On-disk migrations not yet applied to the connected database. */
export async function getPendingMigrations(): Promise<string[]> {
    const onDisk = readOnDiskMigrations();
    const applied = await getAppliedMigrations();
    return pendingMigrationNames(onDisk, applied);
}
