import { db } from "../db.ts";
import { gameSessions, allGames } from "../../drizzle/schema.ts";
import { sql } from "drizzle-orm";

export interface GameMetrics {
  gameId: string;
  gameName: string;
  totalPlays: number;
  totalWinnings: number;
  totalBets: number;
  avgRTP: number;
  avgSessionDuration: number;
  uniquePlayers: number;
  winRate: number;
  avgWinAmount: number;
  playerRetention: number;
  theme: string;
  volatility: string;
}

export interface PerformanceTrend {
  date: string;
  plays: number;
  revenue: number;
  avgWin: number;
  playerCount: number;
}

export interface GameComparison {
  gameId: string;
  gameName: string;
  theme: string;
  rtp: number;
  performance: number; // 0-100 score
  trend: "up" | "down" | "stable";
  recommendation: string;
}

/**
 * Game Performance Analytics Engine
 */
export class GamePerformanceAnalytics {
  /**
   * Get comprehensive metrics for a game
   */
  static async getGameMetrics(gameId: string): Promise<GameMetrics | null> {
    try {
      const sessions = await db
        .select()
        .from(gameSessions)
        .where(sql`game_id = ${gameId}`);

      if (sessions.length === 0) {
        return null;
      }

      const totalPlays = sessions.length;
      const totalWinnings = sessions.reduce((sum, s) => sum + (s.winAmount || 0), 0);
      const totalBets = sessions.reduce((sum, s) => sum + (s.betAmount || 0), 0);
      const avgRTP = totalBets > 0 ? (totalWinnings / totalBets) * 100 : 0;
      const avgSessionDuration =
        sessions.reduce((sum, s) => sum + (s.duration || 0), 0) / totalPlays;
      const uniquePlayers = new Set(sessions.map((s) => s.userId)).size;
      const winRate = (sessions.filter((s) => s.winAmount > 0).length / totalPlays) * 100;
      const avgWinAmount =
        sessions.filter((s) => s.winAmount > 0).length > 0
          ? totalWinnings / sessions.filter((s) => s.winAmount > 0).length
          : 0;

      // Calculate retention (players who played more than once)
      const playerPlayCounts = new Map<number, number>();
      sessions.forEach((s) => {
        playerPlayCounts.set(s.userId, (playerPlayCounts.get(s.userId) || 0) + 1);
      });
      const playerRetention =
        (Array.from(playerPlayCounts.values()).filter((count) => count > 1).length /
          uniquePlayers) *
        100;

      // Get game info
      const game = await db
        .select()
        .from(allGames)
        .where(sql`game_id = ${gameId}`)
        .limit(1);

      return {
        gameId,
        gameName: game[0]?.name || "Unknown",
        totalPlays,
        totalWinnings,
        totalBets,
        avgRTP,
        avgSessionDuration,
        uniquePlayers,
        winRate,
        avgWinAmount,
        playerRetention,
        theme: game[0]?.metadata ? JSON.parse(game[0].metadata).theme : "Unknown",
        volatility: game[0]?.volatility || "Unknown",
      };
    } catch (error) {
      console.error("Error getting game metrics:", error);
      return null;
    }
  }

  /**
   * Get performance trends for a game over time
   */
  static async getPerformanceTrends(
    gameId: string,
    days: number = 30
  ): Promise<PerformanceTrend[]> {
    try {
      const trends: Map<string, PerformanceTrend> = new Map();

      const sessions = await db
        .select()
        .from(gameSessions)
        .where(sql`game_id = ${gameId}`);

      sessions.forEach((session) => {
        const date = new Date(session.createdAt).toISOString().split("T")[0];

        if (!trends.has(date)) {
          trends.set(date, {
            date,
            plays: 0,
            revenue: 0,
            avgWin: 0,
            playerCount: 0,
          });
        }

        const trend = trends.get(date)!;
        trend.plays += 1;
        trend.revenue += session.winAmount - session.betAmount;
        trend.avgWin += session.winAmount;
      });

      // Calculate averages
      trends.forEach((trend) => {
        trend.avgWin = trend.plays > 0 ? trend.avgWin / trend.plays : 0;
        trend.playerCount = new Set(
          sessions
            .filter((s) => new Date(s.createdAt).toISOString().split("T")[0] === trend.date)
            .map((s) => s.userId)
        ).size;
      });

      return Array.from(trends.values()).sort((a, b) =>
        new Date(a.date).getTime() - new Date(b.date).getTime()
      );
    } catch (error) {
      console.error("Error getting performance trends:", error);
      return [];
    }
  }

  /**
   * Compare performance across multiple games
   */
  static async compareGamePerformance(): Promise<GameComparison[]> {
    try {
      const games = await db.select().from(allGames).where(sql`is_active = true`);

      const comparisons: GameComparison[] = [];

      for (const game of games) {
        const metrics = await this.getGameMetrics(game.gameId);

        if (metrics) {
          // Calculate performance score (0-100)
          const rtpScore = Math.min(metrics.avgRTP, 100);
          const winRateScore = metrics.winRate * 2; // Weight win rate
          const retentionScore = metrics.playerRetention * 0.5; // Weight retention
          const performanceScore = (rtpScore + winRateScore + retentionScore) / 3;

          // Determine trend
          const trends = await this.getPerformanceTrends(game.gameId, 7);
          let trend: "up" | "down" | "stable" = "stable";
          if (trends.length >= 2) {
            const recent = trends.slice(-3).reduce((sum, t) => sum + t.revenue, 0);
            const previous = trends.slice(-6, -3).reduce((sum, t) => sum + t.revenue, 0);
            if (recent > previous * 1.1) trend = "up";
            else if (recent < previous * 0.9) trend = "down";
          }

          // Generate recommendation
          let recommendation = "Monitor performance";
          if (performanceScore > 80) {
            recommendation = "Excellent performer - consider remixing with new themes";
          } else if (performanceScore > 60) {
            recommendation = "Good performer - optimize bonus features";
          } else if (performanceScore > 40) {
            recommendation = "Needs improvement - adjust RTP or theme";
          } else {
            recommendation = "Poor performer - consider retiring or major redesign";
          }

          comparisons.push({
            gameId: game.gameId,
            gameName: game.name,
            theme: game.metadata ? JSON.parse(game.metadata).theme : "Unknown",
            rtp: game.rtp || 96.5,
            performance: performanceScore,
            trend,
            recommendation,
          });
        }
      }

      return comparisons.sort((a, b) => b.performance - a.performance);
    } catch (error) {
      console.error("Error comparing game performance:", error);
      return [];
    }
  }

  /**
   * Get top performing games for remixing
   */
  static async getTopPerformersForRemix(limit: number = 5): Promise<GameMetrics[]> {
    try {
      const games = await db.select().from(allGames).where(sql`is_active = true`);

      const metricsArray: GameMetrics[] = [];

      for (const game of games) {
        const metrics = await this.getGameMetrics(game.gameId);
        if (metrics && metrics.totalPlays > 10) {
          // Only consider games with sufficient data
          metricsArray.push(metrics);
        }
      }

      // Sort by performance score
      return metricsArray
        .sort((a, b) => {
          const scoreA = (a.avgRTP + a.winRate * 2 + a.playerRetention * 0.5) / 3;
          const scoreB = (b.avgRTP + b.winRate * 2 + b.playerRetention * 0.5) / 3;
          return scoreB - scoreA;
        })
        .slice(0, limit);
    } catch (error) {
      console.error("Error getting top performers:", error);
      return [];
    }
  }

  /**
   * Get player engagement metrics
   */
  static async getPlayerEngagementMetrics(gameId: string) {
    try {
      const sessions = await db
        .select()
        .from(gameSessions)
        .where(sql`game_id = ${gameId}`);

      const uniquePlayers = new Set(sessions.map((s) => s.userId)).size;
      const totalSessions = sessions.length;
      const avgSessionsPerPlayer = totalSessions / uniquePlayers || 0;

      // Calculate churn rate (players who haven't played in 7 days)
      const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
      const activePlayers = new Set(
        sessions.filter((s) => new Date(s.createdAt) > sevenDaysAgo).map((s) => s.userId)
      ).size;
      const churnRate = ((uniquePlayers - activePlayers) / uniquePlayers) * 100;

      return {
        uniquePlayers,
        totalSessions,
        avgSessionsPerPlayer,
        activePlayers,
        churnRate,
        engagementScore: (activePlayers / uniquePlayers) * 100,
      };
    } catch (error) {
      console.error("Error getting engagement metrics:", error);
      return null;
    }
  }
}

export default GamePerformanceAnalytics;
