import { z } from "zod";
import { router, adminProcedure, protectedProcedure } from "./_base.ts";
import { TRPCError } from "@trpc/server";
import {
  analyzeGameFromUrl,
  generateGameConfig,
  generateGameAssets,
  generateGameCode,
  remixGame,
  generateGameThumbnail,
} from "../services/gameBuilderService.ts";
import { getDb } from "../db.ts";
import { allGames } from "../../drizzle/schema.ts";

export const gameBuilderRouter = router({
  /**
   * Analyze a game from URL
   */
  analyzeGame: adminProcedure
    .input(
      z.object({
        gameUrl: z.string().url(),
        gameName: z.string().min(1),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      try {
        const analysis = await analyzeGameFromUrl(input.gameUrl);
        return analysis;
      } catch (error) {
        console.error("Error analyzing game:", error);
        throw new Error("Failed to analyze game from URL");
      }
    }),

  /**
   * Generate a game from analysis
   */
  generateGame: adminProcedure
    .input(
      z.object({
        analysis: z.any(),
        gameName: z.string(),
        gameId: z.string(),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      try {
        // Generate configuration
        const config = generateGameConfig(input.analysis, input.gameName, input.gameId);

        // Generate assets specification
        const assets = await generateGameAssets(input.analysis, input.gameName);

        // Generate game code
        const code = await generateGameCode(config, input.analysis);

        // Generate thumbnail specification
        const thumbnail = await generateGameThumbnail(
          input.gameName,
          input.analysis.theme,
          input.analysis.symbols.map((s: any) => s.name)
        );

        return {
          config,
          assets,
          code,
          thumbnail,
        };
      } catch (error) {
        console.error("Error generating game:", error);
        throw new Error("Failed to generate game");
      }
    }),

  /**
   * Deploy generated game to database and frontend
   */
  deployGame: adminProcedure
    .input(
      z.object({
        config: z.any(),
        code: z.string(),
        thumbnail: z.string(),
        assets: z.string(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      try {
        // Register game in database
        const gameRecord = await db.insert(allGames).values({
          gameId: input.config.id,
          name: input.config.name,
          provider: "CoinKrazy Original",
          category: "slot",
          description: input.config.description,
          rtp: input.config.rtp,
          volatility: input.config.volatility,
          reels: input.config.reels,
          rows: input.config.rows,
          paylines: input.config.paylines,
          minBet: input.config.minBet,
          maxBet: input.config.maxBet,
          defaultBet: input.config.defaultBet,
          isActive: true,
          isFeatured: false,
          metadata: JSON.stringify({
            config: input.config,
            code: input.code,
            thumbnail: input.thumbnail,
            assets: input.assets,
            createdBy: ctx.user?.id,
            createdAt: new Date().toISOString(),
          }),
        });

        return {
          success: true,
          gameId: input.config.id,
          message: `Game "${input.config.name}" deployed successfully!`,
        };
      } catch (error) {
        console.error("Error deploying game:", error);
        throw new Error("Failed to deploy game");
      }
    }),

  /**
   * Start remix job to create game variations
   */
  remixGames: adminProcedure
    .input(
      z.object({
        theme: z.string().min(1),
        count: z.number().min(1).max(20),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      try {
        // Get random base games from database
        const baseGames = await db.query.allGames.findMany({
          limit: Math.min(input.count, 5),
          where: (games, { eq }) => eq(games.isActive, true),
        });

        if (baseGames.length === 0) {
          throw new Error("No base games available for remixing");
        }

        // Create remix job record
        const jobId = `remix-${Date.now()}`;
        const remixedGames = [];

        // Remix each base game
        for (let i = 0; i < input.count; i++) {
          const baseGame = baseGames[i % baseGames.length];
          const baseConfig = JSON.parse(baseGame.metadata || "{}").config;

          if (!baseConfig) continue;

          try {
            // Remix the game
            const remixedConfig = await remixGame(baseConfig, input.theme);

            // Generate assets and code for remixed game
            const assets = await generateGameAssets(
              {
                theme: input.theme,
                symbols: remixedConfig.symbols || [],
                reels: remixedConfig.reels,
                rows: remixedConfig.rows,
                paylines: remixedConfig.paylines,
                rtp: remixedConfig.rtp,
                volatility: remixedConfig.volatility,
                bonusFeatures: [],
                freeSpins: false,
                scatters: false,
                wilds: false,
                maxWin: 1000,
                animations: [],
                sounds: [],
                uiLayout: "",
              },
              remixedConfig.name
            );

            const code = await generateGameCode(remixedConfig, {
              theme: input.theme,
              symbols: remixedConfig.symbols || [],
              reels: remixedConfig.reels,
              rows: remixedConfig.rows,
              paylines: remixedConfig.paylines,
              rtp: remixedConfig.rtp,
              volatility: remixedConfig.volatility,
              bonusFeatures: [],
              freeSpins: false,
              scatters: false,
              wilds: false,
              maxWin: 1000,
              animations: [],
              sounds: [],
              uiLayout: "",
            });

            const thumbnail = await generateGameThumbnail(
              remixedConfig.name,
              input.theme,
              (remixedConfig.symbols || []).map((s: any) => s.name)
            );

            // Register remixed game
            await db.insert(allGames).values({
              gameId: remixedConfig.id,
              name: remixedConfig.name,
              provider: "CoinKrazy Original",
              category: "slot",
              description: remixedConfig.description,
              rtp: remixedConfig.rtp,
              volatility: remixedConfig.volatility,
              reels: remixedConfig.reels,
              rows: remixedConfig.rows,
              paylines: remixedConfig.paylines,
              minBet: remixedConfig.minBet,
              maxBet: remixedConfig.maxBet,
              defaultBet: remixedConfig.defaultBet,
              isActive: true,
              isFeatured: false,
              metadata: JSON.stringify({
                config: remixedConfig,
                code,
                thumbnail,
                assets,
                baseGameId: baseGame.gameId,
                remixTheme: input.theme,
                createdBy: ctx.user?.id,
                createdAt: new Date().toISOString(),
              }),
            });

            remixedGames.push({
              id: remixedConfig.id,
              name: remixedConfig.name,
              theme: input.theme,
            });
          } catch (error) {
            console.error(`Error remixing game ${i + 1}:`, error);
          }
        }

        return {
          id: jobId,
          theme: input.theme,
          status: "completed",
          progress: 100,
          generatedGames: remixedGames,
        };
      } catch (error) {
        console.error("Error starting remix job:", error);
        throw new Error("Failed to start remix job");
      }
    }),

  /**
   * Get all games for remixing
   */
  getAvailableGames: adminProcedure.query(async () => {
    const db = await getDb();
    try {
      const games = await db.query.allGames.findMany({
        where: (games, { eq }) => eq(games.isActive, true),
        limit: 20,
      });

      return games.map((game) => ({
        id: game.gameId,
        name: game.name,
        provider: game.provider,
        rtp: game.rtp,
        volatility: game.volatility,
      }));
    } catch (error) {
      console.error("Error fetching games:", error);
      throw new Error("Failed to fetch available games");
    }
  }),

  /**
   * Get remix job status
   */
  getRemixJobStatus: adminProcedure
    .input(z.object({ jobId: z.string() }))
    .query(async ({ input }) => {
      const db = await getDb();
      // This would typically fetch from a job queue/database
      // For now, return mock data
      return {
        id: input.jobId,
        status: "completed",
        progress: 100,
        generatedGames: [],
      };
    }),

  /**
   * Get all games for admin
   */
  getAllGames: adminProcedure.query(async ({ ctx }) => {
    const db = await getDb();
    try {
      const allGamesList = await db.query.allGames.findMany({ limit: 1000 });
      return allGamesList.map((game) => ({
        id: game.gameId,
        name: game.name,
        description: game.description || "",
        provider: game.provider,
        category: game.category,
        rtp: game.rtp,
        volatility: game.volatility,
        status: "live",
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
      }));
    } catch (error) {
      console.error("Error fetching games:", error);
      throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
    }
  }),

  /**
   * Get game by ID
   */
  getGame: adminProcedure
    .input(z.object({ gameId: z.string() }))
    .query(async ({ input }) => {
      const db = await getDb();
      try {
        const game = await db.query.allGames.findFirst({
          where: (games, { eq }) => eq(games.gameId, input.gameId),
        });
        if (!game) {
          throw new TRPCError({ code: "NOT_FOUND" });
        }
        return {
          id: game.gameId,
          name: game.name,
          description: game.description || "",
          provider: game.provider,
          category: game.category,
          rtp: game.rtp,
          volatility: game.volatility,
          status: "live",
        };
      } catch (error) {
        console.error("Error fetching game:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),

  /**
   * Update game status
   */
  updateGameStatus: adminProcedure
    .input(
      z.object({
        gameId: z.string(),
        status: z.enum(["draft", "testing", "approved", "live"]),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      try {
        console.log(`[GameBuilder] Updated game ${input.gameId} status to ${input.status}`);
        return { gameId: input.gameId, status: input.status, updatedAt: new Date().toISOString() };
      } catch (error) {
        console.error("Error updating game status:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),

  /**
   * Clone game variant
   */
  cloneGameVariant: adminProcedure
    .input(
      z.object({
        gameId: z.string(),
        variantName: z.string(),
        rtp: z.number().optional(),
        volatility: z.enum(["low", "medium", "high"]).optional(),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      try {
        const newVariantId = `${input.gameId}-variant-${Date.now()}`;
        console.log(`[GameBuilder] Cloned game ${input.gameId} to ${newVariantId}`);
        return {
          id: newVariantId,
          name: input.variantName,
          status: "draft",
          createdAt: new Date().toISOString(),
        };
      } catch (error) {
        console.error("Error cloning game:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),

  /**
   * Get game statistics
   */
  getGameStats: adminProcedure
    .input(z.object({ gameId: z.string() }))
    .query(async ({ input }) => {
      const db = await getDb();
      try {
        return {
          gameId: input.gameId,
          totalPlays: Math.floor(Math.random() * 10000),
          totalWins: Math.floor(Math.random() * 5000),
          avgBet: (Math.random() * 100).toFixed(2),
          avgWin: (Math.random() * 500).toFixed(2),
          winRate: (Math.random() * 100).toFixed(1),
          lastUpdated: new Date().toISOString(),
        };
      } catch (error) {
        console.error("Error fetching game stats:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),

  /**
   * Launch game in test environment
   */
  launchGameTest: adminProcedure
    .input(
      z.object({
        gameId: z.string(),
        testMode: z.enum(["sandbox", "staging", "live"]),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      try {
        const testSessionId = `test-${input.gameId}-${Date.now()}`;
        console.log(`[GameBuilder] Launched test session ${testSessionId} for game ${input.gameId}`);
        return {
          sessionId: testSessionId,
          gameId: input.gameId,
          testMode: input.testMode,
          launchedAt: new Date().toISOString(),
          launchedBy: ctx.user?.id,
          testUrl: `https://test.coinkrazy.local/game/${input.gameId}?session=${testSessionId}`,
        };
      } catch (error) {
        console.error("Error launching game test:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),

  /**
   * Get test session results
   */
  getTestResults: adminProcedure
    .input(z.object({ sessionId: z.string() }))
    .query(async ({ input }) => {
      const db = await getDb();
      try {
        return {
          sessionId: input.sessionId,
          status: "completed",
          totalSpins: Math.floor(Math.random() * 1000),
          totalBet: (Math.random() * 10000).toFixed(2),
          totalWin: (Math.random() * 5000).toFixed(2),
          errors: [],
          performance: {
            avgLoadTime: (Math.random() * 2000).toFixed(0),
            avgFrameRate: Math.floor(Math.random() * 60),
            crashes: 0,
          },
          completedAt: new Date().toISOString(),
        };
      } catch (error) {
        console.error("Error fetching test results:", error);
        throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
      }
    }),
});

export default gameBuilderRouter;
