import { getDb, creditWallet, debitWallet, writeAuditLog } from './db.ts';
import { eq, and, gte, lte } from 'drizzle-orm';

export type TournamentStatus = 'upcoming' | 'active' | 'completed' | 'cancelled';

export interface Tournament {
  id: number;
  name: string;
  description?: string;
  gameId: number;
  status: TournamentStatus;
  entryFee: number;
  maxParticipants?: number;
  currentParticipants: number;
  prizePool: number;
  startTime: Date;
  endTime: Date;
  createdAt: Date;
  updatedAt: Date;
}

export interface TournamentEntry {
  id: number;
  tournamentId: number;
  userId: number;
  score: number;
  spinsCount: number;
  totalWagered: number;
  totalWon: number;
  finalRank?: number;
  prizeWon: number;
  enteredAt: Date;
}

export interface TournamentPrize {
  id: number;
  tournamentId: number;
  rank: number;
  prizeAmount: number;
  prizePercentage?: number;
}

/**
 * Tournament Manager
 * Handles tournament creation, entry, scoring, and prize distribution
 */
export class TournamentManager {
  /**
   * Create a new tournament
   */
  async createTournament(
    name: string,
    gameId: number,
    entryFee: number,
    prizePool: number,
    startTime: Date,
    endTime: Date,
    maxParticipants?: number,
    description?: string
  ): Promise<Tournament> {
    const db = await getDb();
    if (!db) throw new Error('Database connection failed');

    const tournament: Tournament = {
      id: 0, // Will be generated by DB
      name,
      description,
      gameId,
      status: 'upcoming',
      entryFee,
      maxParticipants,
      currentParticipants: 0,
      prizePool,
      startTime,
      endTime,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    // Save to database
    // await db.insert(tournaments).values(tournament);

    return tournament;
  }

  /**
   * Join a tournament
   */
  async joinTournament(
    tournamentId: number,
    userId: number,
    entryFee: number
  ): Promise<{ success: boolean; message: string }> {
    const db = await getDb();
    if (!db) throw new Error('Database connection failed');

    // Check if user already joined
    // const existing = await db.select().from(tournamentEntries)
    //   .where(and(
    //     eq(tournamentEntries.tournamentId, tournamentId),
    //     eq(tournamentEntries.userId, userId)
    //   )).limit(1);

    // if (existing.length > 0) {
    //   return { success: false, message: 'Already joined this tournament' };
    // }

    // Debit entry fee from wallet
    try {
      await debitWallet(
        userId,
        'SC',
        entryFee,
        'tournament_entry',
        `Tournament entry fee`,
        String(userId)
      );
    } catch (error) {
      return { success: false, message: 'Insufficient balance for entry fee' };
    }

    // Create tournament entry
    const entry: TournamentEntry = {
      id: 0,
      tournamentId,
      userId,
      score: 0,
      spinsCount: 0,
      totalWagered: 0,
      totalWon: 0,
      prizeWon: 0,
      enteredAt: new Date(),
    };

    // Save entry to database
    // await db.insert(tournamentEntries).values(entry);

    // Log the entry
    await writeAuditLog({
      actorId: userId,
      actorRole: 'user',
      action: 'tournament_join',
      category: 'gaming',
      details: {
        tournamentId,
        entryFee,
      },
    });

    return { success: true, message: 'Successfully joined tournament' };
  }

  /**
   * Update tournament score
   */
  async updateTournamentScore(
    tournamentId: number,
    userId: number,
    spinWinAmount: number,
    betAmount: number
  ): Promise<void> {
    // Score calculation: net win (win - bet)
    const score = spinWinAmount - betAmount;

    // Update entry with new score
    // await db.update(tournamentEntries)
    //   .set({
    //     score: sql`score + ${score}`,
    //     spinsCount: sql`spinsCount + 1`,
    //     totalWagered: sql`totalWagered + ${betAmount}`,
    //     totalWon: sql`totalWon + ${spinWinAmount}`
    //   })
    //   .where(and(
    //     eq(tournamentEntries.tournamentId, tournamentId),
    //     eq(tournamentEntries.userId, userId)
    //   ));
  }

  /**
   * Get tournament leaderboard
   */
  async getTournamentLeaderboard(
    tournamentId: number,
    limit: number = 100
  ): Promise<Array<TournamentEntry & { rank: number; username: string }>> {
    // Query leaderboard from database
    // Sort by score descending
    // Return with rank position

    return [];
  }

  /**
   * Complete tournament and distribute prizes
   */
  async completeTournament(tournamentId: number): Promise<void> {
    const db = await getDb();
    if (!db) throw new Error('Database connection failed');

    // Get all entries sorted by score
    // const entries = await db.select().from(tournamentEntries)
    //   .where(eq(tournamentEntries.tournamentId, tournamentId))
    //   .orderBy(desc(tournamentEntries.score));

    // Get prize distribution
    // const prizes = await db.select().from(tournamentPrizes)
    //   .where(eq(tournamentPrizes.tournamentId, tournamentId))
    //   .orderBy(asc(tournamentPrizes.rank));

    // Distribute prizes
    // for (let i = 0; i < entries.length && i < prizes.length; i++) {
    //   const entry = entries[i];
    //   const prize = prizes[i];

    //   if (prize.prizeAmount > 0) {
    //     // Credit prize to winner
    //     await creditWallet(
    //       entry.userId,
    //       'SC',
    //       prize.prizeAmount,
    //       'tournament_prize',
    //       `Tournament prize - Rank #${i + 1}`,
    //       String(entry.userId)
    //     );

    //     // Update entry with prize
    //     await db.update(tournamentEntries)
    //       .set({
    //         finalRank: i + 1,
    //         prizeWon: prize.prizeAmount
    //       })
    //       .where(eq(tournamentEntries.id, entry.id));
    //   }
    // }

    // Update tournament status
    // await db.update(tournaments)
    //   .set({ status: 'completed' })
    //   .where(eq(tournaments.id, tournamentId));
  }

  /**
   * Get player tournament stats
   */
  async getPlayerTournamentStats(userId: number): Promise<{
    totalTournamentsJoined: number;
    totalPrizeWon: number;
    bestRank: number;
    winRate: number;
  }> {
    // Query player's tournament history
    // Calculate statistics

    return {
      totalTournamentsJoined: 0,
      totalPrizeWon: 0,
      bestRank: 0,
      winRate: 0,
    };
  }

  /**
   * Generate standard prize distribution
   */
  static generatePrizeDistribution(
    prizePool: number,
    topPlaces: number = 10
  ): TournamentPrize[] {
    const prizes: TournamentPrize[] = [];

    // Standard prize distribution percentages
    const percentages = [
      30, // 1st place
      20, // 2nd place
      15, // 3rd place
      10, // 4th place
      8, // 5th place
      6, // 6th place
      4, // 7th place
      3, // 8th place
      2, // 9th place
      2, // 10th place
    ];

    for (let i = 0; i < Math.min(topPlaces, percentages.length); i++) {
      const percentage = percentages[i];
      const prizeAmount = (prizePool * percentage) / 100;

      prizes.push({
        id: i,
        tournamentId: 0, // Will be set when saving
        rank: i + 1,
        prizeAmount,
        prizePercentage: percentage,
      });
    }

    return prizes;
  }
}

/**
 * Tournament types
 */
export enum TournamentType {
  DAILY = 'daily',
  WEEKLY = 'weekly',
  MONTHLY = 'monthly',
  SPECIAL = 'special',
}

/**
 * Predefined tournament templates
 */
export const TOURNAMENT_TEMPLATES = {
  [TournamentType.DAILY]: {
    name: 'Daily Spin Battle',
    duration: 24 * 60 * 60 * 1000, // 24 hours
    entryFee: 10,
    minPrizePool: 1000,
    maxParticipants: 1000,
  },
  [TournamentType.WEEKLY]: {
    name: 'Weekly Grand Tournament',
    duration: 7 * 24 * 60 * 60 * 1000, // 7 days
    entryFee: 25,
    minPrizePool: 5000,
    maxParticipants: 5000,
  },
  [TournamentType.MONTHLY]: {
    name: 'Monthly Mega Tournament',
    duration: 30 * 24 * 60 * 60 * 1000, // 30 days
    entryFee: 50,
    minPrizePool: 20000,
    maxParticipants: 10000,
  },
  [TournamentType.SPECIAL]: {
    name: 'Special Event Tournament',
    duration: 3 * 24 * 60 * 60 * 1000, // 3 days
    entryFee: 100,
    minPrizePool: 50000,
    maxParticipants: 5000,
  },
};

/**
 * Tournament scheduler
 * Automatically creates tournaments on schedule
 */
export class TournamentScheduler {
  private manager: TournamentManager;

  constructor(manager: TournamentManager) {
    this.manager = manager;
  }

  /**
   * Schedule daily tournaments
   */
  async scheduleDailyTournaments(gameIds: number[]): Promise<void> {
    // Create a daily tournament for each game
    // Schedule it to start at midnight UTC

    for (const gameId of gameIds) {
      const template = TOURNAMENT_TEMPLATES[TournamentType.DAILY];
      const now = new Date();
      const startTime = new Date(now);
      startTime.setUTCHours(0, 0, 0, 0);
      startTime.setDate(startTime.getDate() + 1); // Tomorrow

      const endTime = new Date(startTime);
      endTime.setDate(endTime.getDate() + 1);

      await this.manager.createTournament(
        `${template.name} - Game ${gameId}`,
        gameId,
        template.entryFee,
        template.minPrizePool,
        startTime,
        endTime,
        template.maxParticipants
      );
    }
  }

  /**
   * Schedule weekly tournaments
   */
  async scheduleWeeklyTournaments(gameIds: number[]): Promise<void> {
    // Create a weekly tournament for each game
    // Schedule it to start on Monday at midnight UTC

    for (const gameId of gameIds) {
      const template = TOURNAMENT_TEMPLATES[TournamentType.WEEKLY];
      const now = new Date();
      const startTime = new Date(now);

      // Calculate next Monday
      const day = startTime.getUTCDay();
      const daysUntilMonday = (1 - day + 7) % 7 || 7;
      startTime.setDate(startTime.getDate() + daysUntilMonday);
      startTime.setUTCHours(0, 0, 0, 0);

      const endTime = new Date(startTime);
      endTime.setDate(endTime.getDate() + 7);

      await this.manager.createTournament(
        `${template.name} - Game ${gameId}`,
        gameId,
        template.entryFee,
        template.minPrizePool,
        startTime,
        endTime,
        template.maxParticipants
      );
    }
  }
}

/**
 * Tournament notifications
 */
export interface TournamentNotification {
  type: 'started' | 'ending_soon' | 'completed' | 'prize_won';
  tournamentId: number;
  message: string;
  timestamp: Date;
}

export class TournamentNotificationManager {
  private listeners: Map<number, (notification: TournamentNotification) => void> = new Map();

  /**
   * Subscribe to tournament notifications
   */
  subscribe(userId: number, callback: (notification: TournamentNotification) => void): void {
    this.listeners.set(userId, callback);
  }

  /**
   * Notify user of tournament event
   */
  notify(userId: number, notification: TournamentNotification): void {
    const callback = this.listeners.get(userId);
    if (callback) {
      callback(notification);
    }
  }

  /**
   * Broadcast tournament notification to all participants
   */
  broadcast(userIds: number[], notification: TournamentNotification): void {
    for (const userId of userIds) {
      this.notify(userId, notification);
    }
  }
}

export const tournamentNotificationManager = new TournamentNotificationManager();
