import { router, protectedProcedure } from '../_core/trpc.js.ts';
import { z } from 'zod';
import SlotGameGenerator from '../slotGameGenerator.js';
import SlotGameWalletService from '../slotGameWalletService.js';

const walletService = new SlotGameWalletService();
const gameCache: Map<string, any> = new Map();

export const slotGameRouter = router({
  /**
   * Initialize player wallet
   */
  initializeWallet: protectedProcedure
    .input(
      z.object({
        initialGoldCoins: z.number().default(1000),
        initialSweepsCoins: z.number().default(500),
      })
    )
    .mutation(({ input, ctx }) => {
      return walletService.initializeWallet(ctx.user.id.toString(), input.initialGoldCoins, input.initialSweepsCoins);
    }),

  /**
   * Get player wallet
   */
  getWallet: protectedProcedure.query(({ ctx }) => {
    return walletService.getWallet(ctx.user.id.toString());
  }),

  /**
   * Generate prebuilt games
   */
  generatePrebuiltGames: protectedProcedure.query(() => {
    const games = SlotGameGenerator.generatePrebuiltGames();
    return games.map((game) => ({
      gameId: game.getConfig().gameId,
      gameName: game.getConfig().gameName,
      reels: game.getConfig().reels,
      rows: game.getConfig().rows,
      rtp: game.getRTP(),
      volatility: game.getVolatility(),
      features: game.getConfig().features,
    }));
  }),

  /**
   * Generate game from config
   */
  generateGame: protectedProcedure
    .input(
      z.object({
        gameName: z.string(),
        reels: z.number(),
        rows: z.number(),
        rtp: z.number(),
        volatility: z.enum(['low', 'medium', 'high']),
        features: z.array(z.string()),
        theme: z.string(),
        bonus: z
          .object({
            trigger: z.enum(['scatter', 'bonus', 'collector']),
            spins: z.number(),
            retrigger: z.boolean(),
          })
          .optional(),
      })
    )
    .mutation(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      const game = SlotGameGenerator.generateGame(input);
      const config = game.getConfig();
      gameCache.set(config.gameId, game);

      return {
        gameId: config.gameId,
        gameName: config.gameName,
        reels: config.reels,
        rows: config.rows,
        rtp: config.rtp,
        volatility: config.volatility,
        features: config.features,
      };
    }),

  /**
   * Process spin
   */
  processSpin: protectedProcedure
    .input(
      z.object({
        gameId: z.string(),
        betAmount: z.number(),
        useSweepsCoins: z.boolean().default(true),
      })
    )
    .mutation(async ({ input, ctx }) => {
      let game = gameCache.get(input.gameId);

      if (!game) {
        // Generate default game if not cached
        const games = SlotGameGenerator.generatePrebuiltGames();
        game = games[0];
        gameCache.set(input.gameId, game);
      }

      const spinTransaction = await walletService.processSpin(
        ctx.user.id.toString(),
        input.gameId,
        game,
        input.betAmount,
        input.useSweepsCoins
      );

      return {
        spinId: spinTransaction.spinId,
        reels: spinTransaction.spinResult.reels,
        winAmount: spinTransaction.winAmount,
        newBalance: spinTransaction.spinResult.newBalance,
        bonusTriggered: spinTransaction.spinResult.bonusTriggered,
        freeSpinsAwarded: spinTransaction.freeSpinsAwarded,
        cascadeCount: spinTransaction.spinResult.cascadeCount,
        multiplier: spinTransaction.spinResult.multiplier,
        isWin: spinTransaction.spinResult.isWin,
      };
    }),

  /**
   * Get player transactions
   */
  getPlayerTransactions: protectedProcedure
    .input(z.object({ limit: z.number().default(100) }))
    .query(({ input, ctx }) => {
      return walletService.getPlayerTransactions(ctx.user.id.toString(), input.limit);
    }),

  /**
   * Get spin transaction
   */
  getSpinTransaction: protectedProcedure
    .input(z.object({ spinId: z.string() }))
    .query(({ input }) => {
      return walletService.getSpinTransaction(input.spinId);
    }),

  /**
   * Get player spin history
   */
  getPlayerSpinHistory: protectedProcedure
    .input(z.object({ limit: z.number().default(50) }))
    .query(({ input, ctx }) => {
      return walletService.getPlayerSpinHistory(ctx.user.id.toString(), input.limit);
    }),

  /**
   * Get wallet statistics
   */
  getWalletStatistics: protectedProcedure.query(({ ctx }) => {
    return walletService.getWalletStatistics(ctx.user.id.toString());
  }),

  /**
   * Add bonus (admin only)
   */
  addBonus: protectedProcedure
    .input(
      z.object({
        userId: z.string(),
        amount: z.number(),
        reason: z.string(),
      })
    )
    .mutation(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      return walletService.addBonus(input.userId, input.amount, input.reason);
    }),

  /**
   * Get all wallets (admin only)
   */
  getAllWallets: protectedProcedure.query(({ ctx }) => {
    if (ctx.user.role !== 'admin') {
      throw new Error('Unauthorized');
    }

    return walletService.getAllWallets();
  }),

  /**
   * Get platform statistics (admin only)
   */
  getPlatformStatistics: protectedProcedure.query(({ ctx }) => {
    if (ctx.user.role !== 'admin') {
      throw new Error('Unauthorized');
    }

    return walletService.getPlatformStatistics();
  }),

  /**
   * Export wallet data (admin only)
   */
  exportWalletData: protectedProcedure
    .input(z.object({ userId: z.string() }))
    .query(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      return walletService.exportWalletData(input.userId);
    }),

  /**
   * Get game configuration
   */
  getGameConfig: protectedProcedure
    .input(z.object({ gameId: z.string() }))
    .query(({ input }) => {
      let game = gameCache.get(input.gameId);

      if (!game) {
        const games = SlotGameGenerator.generatePrebuiltGames();
        game = games[0];
      }

      const config = game.getConfig();
      return {
        gameId: config.gameId,
        gameName: config.gameName,
        reels: config.reels,
        rows: config.rows,
        paylines: config.paylines,
        minBet: config.minBet,
        maxBet: config.maxBet,
        rtp: config.rtp,
        volatility: config.volatility,
        features: config.features,
        symbols: config.symbols,
      };
    }),

  /**
   * Calculate hit frequency (admin only)
   */
  calculateHitFrequency: protectedProcedure
    .input(z.object({ gameId: z.string(), spins: z.number().default(1000) }))
    .query(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      let game = gameCache.get(input.gameId);

      if (!game) {
        const games = SlotGameGenerator.generatePrebuiltGames();
        game = games[0];
      }

      return {
        hitFrequency: game.calculateHitFrequency(input.spins),
        spinsAnalyzed: input.spins,
      };
    }),

  /**
   * Calculate average win (admin only)
   */
  calculateAverageWin: protectedProcedure
    .input(z.object({ gameId: z.string(), spins: z.number().default(1000), betAmount: z.number().default(1) }))
    .query(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      let game = gameCache.get(input.gameId);

      if (!game) {
        const games = SlotGameGenerator.generatePrebuiltGames();
        game = games[0];
      }

      return {
        averageWin: game.calculateAverageWin(input.spins, input.betAmount),
        spinsAnalyzed: input.spins,
        betAmount: input.betAmount,
      };
    }),

  /**
   * Update RTP (admin only)
   */
  updateRTP: protectedProcedure
    .input(z.object({ gameId: z.string(), newRTP: z.number() }))
    .mutation(({ input, ctx }) => {
      if (ctx.user.role !== 'admin') {
        throw new Error('Unauthorized');
      }

      let game = gameCache.get(input.gameId);

      if (!game) {
        throw new Error('Game not found');
      }

      game.updateRTP(input.newRTP);

      return {
        gameId: input.gameId,
        newRTP: input.newRTP,
      };
    }),
});

export default slotGameRouter;
