import { randomBytes } from 'node:crypto';
import path from 'node:path';
import { createDb, hashPassword } from '@pintrush/db';
import { SignJWT } from 'jose';

try {
  process.loadEnvFile(path.resolve(import.meta.dirname, '../.env'));
} catch {
  // CI injects env vars directly
}

export interface GameFixture {
  venueId: string;
  joinCode: string;
  roomId: string;
  eventId: string;
  hostEmail: string;
  hostPassword: string;
  tvPath: string;
  cleanup(): Promise<void>;
}

/**
 * A throwaway venue for one end-to-end run: room, OWNER host with a known test password, always-on off
 * (the championship is the only game in the room) and a short two-round championship.
 */
export async function createGameFixture(): Promise<GameFixture> {
  const db = createDb();
  const tag = randomBytes(3).toString('hex').toUpperCase();
  const joinCode = `E2E${tag}`;
  const hostEmail = `e2e-host-${tag.toLowerCase()}@example.test`;
  const hostPassword = `e2e-${randomBytes(9).toString('base64url')}`;
  const venue = await db.venue.create({
    data: {
      slug: `e2e-${tag.toLowerCase()}`,
      name: `E2E Tavern ${tag}`,
      joinCode,
      settings: { alwaysOn: { enabled: false, packKey: 'originals-v1', schedule: [] }, mergeSolos: true },
    },
  });
  const room = await db.room.create({ data: { venueId: venue.id, name: 'Main Bar', slug: 'main' } });
  await db.venueUser.create({ data: { venueId: venue.id, email: hostEmail, name: 'E2E Host', role: 'OWNER', passwordHash: await hashPassword(hostPassword) } });
  const event = await db.event.create({
    data: {
      venueId: venue.id,
      roomId: room.id,
      kind: 'CHAMPIONSHIP',
      name: 'E2E Championship',
      scheduledAt: new Date(Date.now() + 2 * 3_600_000),
      config: {
        plan: [
          { kind: 'RUSH', packKey: 'originals-v1', label: 'The Rush', segment: 0 },
          { kind: 'TABLE_WARS', packKey: 'originals-v1', label: 'Table Wars', segment: 1 },
        ],
        mergeSolos: true,
      },
    },
  });
  const secret = new TextEncoder().encode(process.env.AUTH_SECRET || 'dev-only-insecure-secret-change-me-0123456789');
  const tvToken = await new SignJWT({ scope: 'tv', roomId: room.id, venueId: venue.id, v: room.tvTokenVersion })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuer('pintrush')
    .setAudience('pintrush-game')
    .setIssuedAt()
    .sign(secret);

  return {
    venueId: venue.id,
    joinCode,
    roomId: room.id,
    eventId: event.id,
    hostEmail,
    hostPassword,
    tvPath: `/tv/${room.id}?t=${tvToken}`,
    async cleanup() {
      // Cascades remove the room, event, session, players and their play records.
      await db.venue.delete({ where: { id: venue.id } }).catch(() => undefined);
      await db.$disconnect();
    },
  };
}
