import { protectedProcedure, publicProcedure, router } from "../_core/trpc.ts";
import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { getDb } from "../db.ts";
import { eq, desc, sql, and } from "drizzle-orm";

/**
 * Easter Eggsplosion Game Router
 * Handles game spins, balance updates, and win tracking
 */
export const easterGameRouter = router({
  /**
   * Start a new spin
   * Deducts bet from player balance and returns spin result
   */
  spin: protectedProcedure
    .input(
      z.object({
        bet: z.number().min(0.1).max(100),
        gameId: z.string().default("easter-eggsplosion"),
      })
    )
    .mutation(async ({ ctx, input }) => {
      try {
        // Validate user has sufficient balance
        if (!ctx.user) {
          throw new TRPCError({
            code: "UNAUTHORIZED",
            message: "User not authenticated",
          });
        }

        // TODO: Fetch user balance from database
        // const userBalance = await getUserBalance(ctx.user.id);
        
        // if (userBalance < input.bet) {
        //   throw new TRPCError({
        //     code: "BAD_REQUEST",
        //     message: "Insufficient balance",
        //   });
        // }

        // Generate spin result (RNG)
        const spinResult = generateSpinResult(input.bet);

        // TODO: Update user balance in database
        // await updateUserBalance(ctx.user.id, -input.bet + spinResult.totalWin);

        // TODO: Log spin to game_plays table
        // await logGamePlay({
        //   userId: ctx.user.id,
        //   gameId: input.gameId,
        //   bet: input.bet,
        //   win: spinResult.totalWin,
        //   reels: spinResult.reels,
        //   timestamp: new Date(),
        // });

        return {
          success: true,
          spinResult,
          newBalance: 1000 + spinResult.totalWin - input.bet, // Mock balance
          timestamp: new Date(),
        };
      } catch (error) {
        console.error("Spin error:", error);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to process spin",
        });
      }
    }),

  /**
   * Get game statistics
   */
  getStats: publicProcedure
    .input(
      z.object({
        gameId: z.string().default("easter-eggsplosion"),
      })
    )
    .query(async ({ input }) => {
      try {
        // TODO: Fetch from database
        return {
          gameId: input.gameId,
          totalPlays: 0,
          totalWinnings: 0,
          averageRTP: 96.5,
          playerCount: 0,
          lastUpdated: new Date(),
        };
      } catch (error) {
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to fetch game stats",
        });
      }
    }),

  /**
   * Get player game history
   */
  getHistory: protectedProcedure
    .input(
      z.object({
        gameId: z.string().default("easter-eggsplosion"),
        limit: z.number().min(1).max(100).default(20),
      })
    )
    .query(async ({ ctx, input }) => {
      try {
        if (!ctx.user) {
          throw new TRPCError({
            code: "UNAUTHORIZED",
            message: "User not authenticated",
          });
        }

        // TODO: Fetch from game_plays table
        return {
          plays: [],
          totalWins: 0,
          totalBet: 0,
          gameId: input.gameId,
        };
      } catch (error) {
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to fetch game history",
        });
      }
    }),

  /**
   * Get Easter Eggsplosion leaderboard - top 10 egg collectors
   * Queries real database for game sessions
   */
  getLeaderboard: publicProcedure
    .input(
      z.object({
        limit: z.number().min(1).max(100).default(10),
      })
    )
    .query(async ({ ctx, input }) => {
      try {
        const db = await getDb();
        
        // If database is unavailable, return mock data
        if (!db) {
          console.warn("[Easter Leaderboard] Database unavailable, using mock data");
          return {
            leaderboard: getMockLeaderboard().slice(0, input.limit),
            totalPlayers: 10,
            lastUpdated: new Date(),
            source: "mock",
          };
        }

        // Import schema dynamically
        const schema = await import("../../drizzle/schema");

        // Get Easter game ID
        const easterGame = await db
          .select({ id: schema.casinoGames.id })
          .from(schema.casinoGames)
          .where(eq(schema.casinoGames.gameName, "Easter Eggsplosion"))
          .limit(1);

        if (!easterGame.length) {
          console.warn("[Easter Leaderboard] Easter game not found in database");
          return {
            leaderboard: getMockLeaderboard().slice(0, input.limit),
            totalPlayers: 10,
            lastUpdated: new Date(),
            source: "mock",
          };
        }

        const easterGameId = easterGame[0].id;

        // Query aggregated game sessions for leaderboard
        const leaderboardData = await db
          .select({
            userId: schema.gameSessions.userId,
            username: schema.users.username,
            avatarUrl: schema.users.avatarUrl,
            eggsCollected: sql<number>`CAST(COALESCE(SUM(CAST(JSON_EXTRACT(${schema.gameSessions.outcome}, '$.eggsCollected') AS UNSIGNED)), 0) AS UNSIGNED)`,
            spins: sql<number>`COUNT(*)`,
            totalWinnings: sql<number>`CAST(COALESCE(SUM(CAST(${schema.gameSessions.winAmount} AS DECIMAL)), 0) AS UNSIGNED)`,
          })
          .from(schema.gameSessions)
          .innerJoin(schema.users, eq(schema.gameSessions.userId, schema.users.id))
          .where(eq(schema.gameSessions.gameId, easterGameId))
          .groupBy(schema.gameSessions.userId)
          .orderBy(desc(sql`eggsCollected`))
          .limit(input.limit);

        // Format results with ranking and badges
        const leaderboard = leaderboardData.map((entry, index) => ({
          rank: index + 1,
          userId: entry.userId,
          username: entry.username || `Player ${entry.userId}`,
          avatarUrl: entry.avatarUrl || `https://api.dicebear.com/7.x/avataaars/svg?seed=Player${entry.userId}`,
          eggsCollected: entry.eggsCollected || 0,
          spins: entry.spins || 0,
          totalWinnings: entry.totalWinnings || 0,
          badge: index === 0 ? "gold" : index === 1 ? "silver" : index === 2 ? "bronze" : undefined,
        }));

        return {
          leaderboard,
          totalPlayers: leaderboard.length,
          lastUpdated: new Date(),
          source: "database",
        };
      } catch (error) {
        console.error("[Easter Leaderboard] Fetch error:", error);
        // Gracefully fall back to mock data on error
        return {
          leaderboard: getMockLeaderboard().slice(0, input.limit),
          totalPlayers: 10,
          lastUpdated: new Date(),
          source: "mock",
          error: "Database query failed, showing mock data",
        };
      }
    }),

  /**
   * Get user's current rank and stats
   * Queries real database for user's Easter game performance
   */
  getUserRank: protectedProcedure
    .query(async ({ ctx }) => {
      try {
        if (!ctx.user) {
          throw new TRPCError({
            code: "UNAUTHORIZED",
            message: "User not authenticated",
          });
        }

        const db = await getDb();
        
        // If database is unavailable, return mock data
        if (!db) {
          console.warn("[Easter User Rank] Database unavailable, using mock data");
          return {
            rank: 42,
            userId: ctx.user.id,
            username: ctx.user.username || "Player",
            eggsCollected: 450,
            spins: 89,
            totalWinnings: 2250,
            percentileRank: 78,
            source: "mock",
          };
        }

        // Import schema dynamically
        const schema = await import("../../drizzle/schema");

        // Get Easter game ID
        const easterGame = await db
          .select({ id: schema.casinoGames.id })
          .from(schema.casinoGames)
          .where(eq(schema.casinoGames.gameName, "Easter Eggsplosion"))
          .limit(1);

        if (!easterGame.length) {
          console.warn("[Easter User Rank] Easter game not found");
          return {
            rank: 0,
            userId: ctx.user.id,
            username: ctx.user.username || "Player",
            eggsCollected: 0,
            spins: 0,
            totalWinnings: 0,
            percentileRank: 0,
            source: "mock",
          };
        }

        const easterGameId = easterGame[0].id;

        // Get user's aggregated stats
        const userStats = await db
          .select({
            eggsCollected: sql<number>`CAST(COALESCE(SUM(CAST(JSON_EXTRACT(${schema.gameSessions.outcome}, '$.eggsCollected') AS UNSIGNED)), 0) AS UNSIGNED)`,
            spins: sql<number>`COUNT(*)`,
            totalWinnings: sql<number>`CAST(COALESCE(SUM(CAST(${schema.gameSessions.winAmount} AS DECIMAL)), 0) AS UNSIGNED)`,
          })
          .from(schema.gameSessions)
          .where(
            and(
              eq(schema.gameSessions.userId, ctx.user.id),
              eq(schema.gameSessions.gameId, easterGameId)
            )
          );

        const stats = userStats[0] || { eggsCollected: 0, spins: 0, totalWinnings: 0 };

        // Get total players for percentile calculation
        const totalPlayers = await db
          .select({ count: sql<number>`COUNT(DISTINCT ${schema.gameSessions.userId})` })
          .from(schema.gameSessions)
          .where(eq(schema.gameSessions.gameId, easterGameId));

        const totalCount = totalPlayers[0]?.count || 1;

        // Get user's rank (count how many players have more eggs)
        const rankResult = await db
          .select({ rank: sql<number>`COUNT(*) + 1` })
          .from(schema.gameSessions)
          .where(
            and(
              eq(schema.gameSessions.gameId, easterGameId),
              sql`CAST(JSON_EXTRACT(${schema.gameSessions.outcome}, '$.eggsCollected') AS UNSIGNED) > ${stats.eggsCollected}`
            )
          );

        const userRank = rankResult[0]?.rank || totalCount;
        const percentileRank = Math.round(((totalCount - userRank) / totalCount) * 100);

        return {
          rank: userRank,
          userId: ctx.user.id,
          username: ctx.user.username || "Player",
          eggsCollected: stats.eggsCollected || 0,
          spins: stats.spins || 0,
          totalWinnings: stats.totalWinnings || 0,
          percentileRank: Math.max(0, percentileRank),
          source: "database",
        };
      } catch (error) {
        console.error("[Easter User Rank] Fetch error:", error);
        // Return mock data on error
        return {
          rank: 0,
          userId: ctx.user?.id || 0,
          username: ctx.user?.username || "Player",
          eggsCollected: 0,
          spins: 0,
          totalWinnings: 0,
          percentileRank: 0,
          source: "mock",
          error: "Database query failed",
        };
      }
    }),

  /**
   * Claim bonus feature reward
   */
  claimBonus: protectedProcedure
    .input(
      z.object({
        bonusType: z.enum(["respin", "freeSpins", "collectAndWin", "wheelSpin"]),
        amount: z.number().min(0),
      })
    )
    .mutation(async ({ ctx, input }) => {
      try {
        if (!ctx.user) {
          throw new TRPCError({
            code: "UNAUTHORIZED",
            message: "User not authenticated",
          });
        }

        // TODO: Update user balance and log bonus claim
        return {
          success: true,
          bonusType: input.bonusType,
          amount: input.amount,
          newBalance: 1000 + input.amount, // Mock
        };
      } catch (error) {
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to claim bonus",
        });
      }
    }),
});

/**
 * Generate spin result with RNG
 * Returns reels and win amount based on game logic
 */
function generateSpinResult(bet: number) {
  const symbols = ["wild", "scatter", "red-egg", "blue-egg", "green-egg", "purple-egg", "yellow-egg", "bunny"];
  
  // Generate random reels
  const reels = Array(3).fill(null).map(() =>
    Array(3).fill(null).map(() => symbols[Math.floor(Math.random() * symbols.length)])
  );

  // Calculate win (simplified - check for matching symbols)
  let totalWin = 0;
  
  // Check horizontal paylines
  for (let row = 0; row < 3; row++) {
    if (reels[0][row] === reels[1][row] && reels[1][row] === reels[2][row]) {
      const symbol = reels[0][row];
      const multiplier = getSymbolMultiplier(symbol);
      totalWin += bet * multiplier;
    }
  }

  // Check diagonal paylines
  if (reels[0][0] === reels[1][1] && reels[1][1] === reels[2][2]) {
    const symbol = reels[0][0];
    const multiplier = getSymbolMultiplier(symbol);
    totalWin += bet * multiplier;
  }

  if (reels[0][2] === reels[1][1] && reels[1][1] === reels[2][0]) {
    const symbol = reels[0][2];
    const multiplier = getSymbolMultiplier(symbol);
    totalWin += bet * multiplier;
  }

  return {
    reels,
    totalWin,
    paylines: totalWin > 0 ? 1 : 0,
  };
}

/**
 * Get payout multiplier for symbol
 */
function getSymbolMultiplier(symbol: string): number {
  const multipliers: Record<string, number> = {
    wild: 50,
    scatter: 30,
    "red-egg": 20,
    "blue-egg": 15,
    "green-egg": 12,
    "purple-egg": 10,
    "yellow-egg": 8,
    bunny: 25,
  };
  return multipliers[symbol] || 1;
}

/**
 * Get mock leaderboard data for fallback
 */
function getMockLeaderboard() {
  return [
    {
      rank: 1,
      userId: 1,
      username: "EggMaster",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=EggMaster",
      eggsCollected: 2450,
      spins: 487,
      totalWinnings: 12500,
      badge: "gold",
    },
    {
      rank: 2,
      userId: 2,
      username: "BunnyHunter",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=BunnyHunter",
      eggsCollected: 2180,
      spins: 421,
      totalWinnings: 10800,
      badge: "silver",
    },
    {
      rank: 3,
      userId: 3,
      username: "EasterChamp",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=EasterChamp",
      eggsCollected: 1950,
      spins: 398,
      totalWinnings: 9750,
      badge: "bronze",
    },
    {
      rank: 4,
      userId: 4,
      username: "LuckySpinner",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=LuckySpinner",
      eggsCollected: 1720,
      spins: 356,
      totalWinnings: 8600,
      badge: undefined,
    },
    {
      rank: 5,
      userId: 5,
      username: "EggCollector",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=EggCollector",
      eggsCollected: 1580,
      spins: 312,
      totalWinnings: 7900,
      badge: undefined,
    },
    {
      rank: 6,
      userId: 6,
      username: "SpringVibes",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=SpringVibes",
      eggsCollected: 1420,
      spins: 289,
      totalWinnings: 7100,
      badge: undefined,
    },
    {
      rank: 7,
      userId: 7,
      username: "FestivePlayer",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=FestivePlayer",
      eggsCollected: 1290,
      spins: 267,
      totalWinnings: 6450,
      badge: undefined,
    },
    {
      rank: 8,
      userId: 8,
      username: "WinnerWinner",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=WinnerWinner",
      eggsCollected: 1150,
      spins: 245,
      totalWinnings: 5750,
      badge: undefined,
    },
    {
      rank: 9,
      userId: 9,
      username: "GoldenEgg",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=GoldenEgg",
      eggsCollected: 980,
      spins: 198,
      totalWinnings: 4900,
      badge: undefined,
    },
    {
      rank: 10,
      userId: 10,
      username: "CasualPlayer",
      avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed=CasualPlayer",
      eggsCollected: 850,
      spins: 167,
      totalWinnings: 4250,
      badge: undefined,
    },
  ];
}

export default easterGameRouter;
