import { protectedProcedure, publicProcedure, router } from "../_core/trpc.ts";
import { z } from "zod";
import { getPokerTables, getPokerTournaments, getHandHistory, debitWallet, creditWallet, writeAuditLog, getDb } from "../db.ts";
import { eq, sql } from "drizzle-orm";
import { pokerTables, pokerTournaments } from "../../drizzle/schema.ts";

export const pokerRouter = router({
  getTables: publicProcedure
    .input(z.object({ currency: z.enum(["GC", "SC"]).optional() }))
    .query(async ({ input }) => {
      return getPokerTables(input.currency);
    }),

  getTournaments: publicProcedure.query(async () => {
    return getPokerTournaments();
  }),

  getHandHistory: protectedProcedure
    .input(z.object({ tableId: z.number(), limit: z.number().default(20) }))
    .query(async ({ input }) => {
      return getHandHistory(input.tableId, input.limit);
    }),

  joinTable: protectedProcedure
    .input(z.object({
      tableId: z.number(),
      buyInAmount: z.number().min(1),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const tables = await db.select().from(pokerTables).where(eq(pokerTables.id, input.tableId)).limit(1);
      const table = tables[0];
      if (!table) throw new Error("Table not found");
      if (table.status === "closed") throw new Error("Table is closed");
      if (table.currentPlayers >= table.maxPlayers) throw new Error("Table is full");

      const minBuyIn = parseFloat(table.minBuyIn);
      const maxBuyIn = parseFloat(table.maxBuyIn);
      if (input.buyInAmount < minBuyIn || input.buyInAmount > maxBuyIn) {
        throw new Error(`Buy-in must be between ${minBuyIn} and ${maxBuyIn} ${table.currency}`);
      }

      await debitWallet(ctx.user.id, table.currency, input.buyInAmount, "poker_buyin", `Poker buy-in: ${table.name}`, String(input.tableId));
      await db.update(pokerTables).set({ currentPlayers: sql`${pokerTables.currentPlayers} + 1`, status: "active" }).where(eq(pokerTables.id, input.tableId));

      await writeAuditLog({ actorId: ctx.user.id, actorRole: "user", action: "poker_join_table", category: "game", details: { tableId: input.tableId, buyIn: input.buyInAmount } });
      return { success: true, tableId: input.tableId, buyInAmount: input.buyInAmount, currency: table.currency };
    }),

  leaveTable: protectedProcedure
    .input(z.object({ tableId: z.number(), cashOutAmount: z.number().min(0) }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const tables = await db.select().from(pokerTables).where(eq(pokerTables.id, input.tableId)).limit(1);
      const table = tables[0];
      if (!table) throw new Error("Table not found");

      if (input.cashOutAmount > 0) {
        await creditWallet(ctx.user.id, table.currency, input.cashOutAmount, "poker_win", `Poker cash-out: ${table.name}`, String(input.tableId));
      }
      await db.update(pokerTables).set({ currentPlayers: sql`GREATEST(0, ${pokerTables.currentPlayers} - 1)` }).where(eq(pokerTables.id, input.tableId));
      return { success: true };
    }),

  registerTournament: protectedProcedure
    .input(z.object({ tournamentId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const tournaments = await db.select().from(pokerTournaments).where(eq(pokerTournaments.id, input.tournamentId)).limit(1);
      const tournament = tournaments[0];
      if (!tournament) throw new Error("Tournament not found");
      if (tournament.status !== "registering") throw new Error("Tournament registration is closed");
      if (tournament.registeredPlayers >= tournament.maxPlayers) throw new Error("Tournament is full");

      const buyIn = parseFloat(tournament.buyIn);
      if (buyIn > 0) {
        await debitWallet(ctx.user.id, tournament.currency, buyIn, "poker_buyin", `Tournament buy-in: ${tournament.name}`, String(input.tournamentId));
      }
      await db.update(pokerTournaments).set({
        registeredPlayers: sql`${pokerTournaments.registeredPlayers} + 1`,
        prizePool: sql`${pokerTournaments.prizePool} + ${buyIn}`,
      }).where(eq(pokerTournaments.id, input.tournamentId));

      return { success: true };
    }),
});
