import * as fs from 'node:fs';
import * as path from 'node:path';
import { execFileSync } from 'node:child_process';
import { PrismaClient } from '@prisma/client';

/**
 * Per-test-suite SQLite DB. Creates a fresh schema-only DB at a temp
 * path, returns a PrismaClient pointed at it, and exposes a teardown.
 *
 * Each test file calls `setupTestDb()` in beforeAll and the returned
 * `cleanup()` in afterAll. State is NOT cleared between individual
 * tests inside a file — write tests so they either tear down their
 * own rows or use unique values.
 */

let counter = 0;

export interface TestDb {
  prisma: PrismaClient;
  dbPath: string;
  cleanup: () => Promise<void>;
}

export async function setupTestDb(): Promise<TestDb> {
  const id = `${process.pid}-${Date.now()}-${++counter}`;
  const dbPath = path.resolve('/tmp', `pow-test-${id}.db`);

  // Apply current Prisma schema to the temp DB. `prisma db push` is the
  // right tool here (skips migration history bookkeeping).
  execFileSync(
    'npx',
    [
      'prisma',
      'db',
      'push',
      '--skip-generate',
      '--accept-data-loss',
    ],
    {
      env: { ...process.env, DATABASE_URL: `file:${dbPath}` },
      stdio: 'pipe',
    },
  );

  const prisma = new PrismaClient({
    datasources: { db: { url: `file:${dbPath}` } },
    log: ['error'],
  });

  return {
    prisma,
    dbPath,
    cleanup: async () => {
      await prisma.$disconnect();
      try {
        fs.unlinkSync(dbPath);
      } catch {
        /* already gone */
      }
      // Clean up SQLite sidecar files too.
      for (const ext of ['-journal', '-wal', '-shm']) {
        try {
          fs.unlinkSync(dbPath + ext);
        } catch {
          /* */
        }
      }
    },
  };
}
