/**
 * Platform Systems Tests
 * Tests for admin control panel, advanced analytics, and gamification engine
 */

import { describe, it, expect, beforeEach } from 'vitest';
import {
  createAdminUser,
  getPermissionsForRole,
  hasPermission,
  createAuditLog,
  updateGameStatus,
  suspendPlayer,
  banPlayer,
  addPlayerRestriction,
  detectFraudRisk,
  generateFinancialReport,
  checkSystemHealth,
  type AdminUser,
  type PlayerModeration,
} from './adminControlPanel';
import {
  createPlayerCohort,
  updateCohortRetention,
  updateCohortRevenue,
  predictPlayerLTV,
  predictPlayerChurn,
  segmentPlayersByLTV,
  identifyAtRiskPlayers,
  calculateF1Score,
  predictPlayerEngagement,
  generateCohortAnalysisReport,
} from './advancedAnalyticsML';
import {
  createAchievement,
  unlockAchievement,
  updateAchievementProgress,
  createDailyChallenge,
  trackChallengeProgress,
  createSeasonalEvent,
  updateEventLeaderboard,
  createBattlePass,
  progressBattlePass,
  claimBattlePassReward,
  PREDEFINED_ACHIEVEMENTS,
  calculateAchievementProgression,
  generateAchievementLeaderboard,
  createGameSeason,
  type PlayerAchievement,
  type PlayerChallenge,
  type PlayerBattlePass,
} from './gamificationEngine';

describe('Platform Systems', () => {
  describe('Admin Control Panel', () => {
    let admin: AdminUser;

    beforeEach(() => {
      admin = createAdminUser('admin1', 'admin@example.com', 'admin');
    });

    it('should create admin user', () => {
      expect(admin.username).toBe('admin1');
      expect(admin.role).toBe('admin');
      expect(admin.isActive).toBe(true);
    });

    it('should get permissions for role', () => {
      const permissions = getPermissionsForRole('admin');
      expect(permissions).toContain('manage_games');
      expect(permissions).toContain('manage_players');
    });

    it('should check admin permissions', () => {
      expect(hasPermission(admin, 'manage_games')).toBe(true);
      expect(hasPermission(admin, 'manage_admins')).toBe(false);
    });

    it('should create audit log', () => {
      const log = createAuditLog(
        admin.id,
        admin.username,
        'suspend',
        'player',
        '123',
        { reason: 'fraud' },
        '192.168.1.1',
        'Mozilla/5.0'
      );

      expect(log.action).toBe('suspend');
      expect(log.targetType).toBe('player');
    });

    it('should suspend player', () => {
      const moderation: PlayerModeration = {
        playerId: 1,
        username: 'player1',
        status: 'active',
        restrictions: [],
        warnings: 0,
        lastModeration: new Date(),
      };

      suspendPlayer(moderation, 'Suspicious activity', 7);

      expect(moderation.status).toBe('suspended');
      expect(moderation.warnings).toBe(1);
      expect(moderation.suspendedUntil).toBeDefined();
    });

    it('should ban player', () => {
      const moderation: PlayerModeration = {
        playerId: 1,
        username: 'player1',
        status: 'active',
        restrictions: [],
        warnings: 0,
        lastModeration: new Date(),
      };

      banPlayer(moderation, 'Cheating detected');

      expect(moderation.status).toBe('banned');
      expect(moderation.reason).toBe('Cheating detected');
    });

    it('should add player restriction', () => {
      const moderation: PlayerModeration = {
        playerId: 1,
        username: 'player1',
        status: 'active',
        restrictions: [],
        warnings: 0,
        lastModeration: new Date(),
      };

      const restriction = addPlayerRestriction(moderation, 'bet_limit', 100, 30);

      expect(moderation.restrictions).toHaveLength(1);
      expect(restriction.type).toBe('bet_limit');
    });

    it('should detect fraud risk', () => {
      const fraud = detectFraudRisk(1, 'player1', {
        unusualBettingPattern: true,
        multipleAccounts: true,
        rapidWithdrawals: false,
        chargebackHistory: false,
        veryNewAccount: false,
        largeWinnings: false,
        locationMismatch: false,
        deviceMismatch: false,
      });

      expect(fraud.riskScore).toBeGreaterThan(0);
      expect(fraud.riskFactors.length).toBeGreaterThan(0);
    });

    it('should generate financial report', () => {
      const report = generateFinancialReport(
        'monthly',
        new Date(),
        new Date(),
        10000,
        5000,
        2000,
        8000,
        100,
        20,
        50
      );

      expect(report.totalRevenue).toBe(10000);
      expect(report.profitMargin).toBeGreaterThan(0);
    });

    it('should check system health', () => {
      const health = checkSystemHealth(99.9, 50, 0.1, 1000);

      expect(health.uptime).toBe(99.9);
      expect(health.databaseStatus).toBe('healthy');
    });
  });

  describe('Advanced Analytics', () => {
    it('should create player cohort', () => {
      const cohort = createPlayerCohort(new Date(), 100, 'organic');

      expect(cohort.cohortSize).toBe(100);
      expect(cohort.acquisitionChannel).toBe('organic');
    });

    it('should update cohort retention', () => {
      const cohort = createPlayerCohort(new Date(), 100, 'organic');
      updateCohortRetention(cohort, 7, 80);

      expect(cohort.retention.day7).toBe(80);
    });

    it('should predict player LTV', () => {
      const prediction = predictPlayerLTV(1, 'player1', 100, 5, 'slots', 60, 80, 2);

      expect(prediction.predictedLTV).toBeGreaterThan(0);
      expect(prediction.confidence).toBeGreaterThan(0);
      expect(prediction.recommendations.length).toBeGreaterThan(0);
    });

    it('should predict player churn', () => {
      const churn = predictPlayerChurn(1, 'player1', 45, 30, 0.5, 100, 30);

      expect(churn.churnRisk).toBeGreaterThan(0);
      expect(churn.riskFactors.length).toBeGreaterThan(0);
    });

    it('should segment players by LTV', () => {
      const pred1 = predictPlayerLTV(1, 'player1', 100, 5, 'slots', 60, 80, 2);
      const pred2 = predictPlayerLTV(2, 'player2', 10, 1, 'slots', 30, 40, 0);

      const segments = segmentPlayersByLTV([pred1, pred2]);

      expect(segments.high_value.length).toBeGreaterThan(0);
      expect(segments.low_value.length).toBeGreaterThan(0);
    });

    it('should identify at-risk players', () => {
      const churn1 = predictPlayerChurn(1, 'player1', 60, 45, 0.2, 200, 20);
      const churn2 = predictPlayerChurn(2, 'player2', 5, 2, 5, 50, 60);

      const atRisk = identifyAtRiskPlayers([churn1, churn2], 70);

      expect(atRisk.length).toBeGreaterThanOrEqual(0);
    });

    it('should calculate F1 score', () => {
      const f1 = calculateF1Score(0.9, 0.85);
      expect(f1).toBeGreaterThan(0);
      expect(f1).toBeLessThanOrEqual(1);
    });

    it('should predict player engagement', () => {
      const engagement = predictPlayerEngagement(1, 'player1', 10, 50, ['game1', 'game2'], 'America/New_York');

      expect(engagement.engagementScore).toBeGreaterThanOrEqual(0);
      expect(engagement.predictedDailyActiveProb).toBeGreaterThanOrEqual(0);
      expect(engagement.recommendedOffers.length).toBeGreaterThan(0);
    });

    it('should generate cohort analysis report', () => {
      const cohort1 = createPlayerCohort(new Date(), 100, 'organic');
      updateCohortRetention(cohort1, 30, 50);
      updateCohortRevenue(cohort1, 30, 5000);

      const report = generateCohortAnalysisReport([cohort1]);

      expect(report.averageLTV).toBeGreaterThanOrEqual(0);
      expect(report.trends.length).toBeGreaterThanOrEqual(0);
    });
  });

  describe('Gamification Engine', () => {
    let playerAch: PlayerAchievement;
    let playerChallenge: PlayerChallenge;
    let playerBattlePass: PlayerBattlePass;

    beforeEach(() => {
      playerAch = unlockAchievement(1, 'first_win');
      playerChallenge = {
        id: 'pc1',
        playerId: 1,
        challengeId: 'challenge1',
        progress: 0,
        completed: false,
        rewardsClaimed: false,
      };
      playerBattlePass = {
        id: 'pbp1',
        playerId: 1,
        battlePassId: 'bp1',
        currentTier: 1,
        xp: 0,
        rewardsClaimed: [],
        purchased: false,
      };
    });

    it('should create achievement', () => {
      const achievement = createAchievement(
        'Test Achievement',
        'Test description',
        '🏆',
        'rare',
        50,
        [{ type: 'plays', value: 10, description: 'Play 10 games' }],
        [{ type: 'coins', amount: 100, description: 'Bonus coins' }]
      );

      expect(achievement.name).toBe('Test Achievement');
      expect(achievement.rarity).toBe('rare');
    });

    it('should unlock achievement', () => {
      expect(playerAch.isCompleted).toBe(true);
      expect(playerAch.unlockedAt).toBeDefined();
    });

    it('should update achievement progress', () => {
      updateAchievementProgress(playerAch, 5, 10);
      expect(playerAch.progress).toBe(50);
    });

    it('should create daily challenge', () => {
      const challenge = createDailyChallenge(
        new Date(),
        'Win 5 Games',
        'Win 5 games today',
        { type: 'plays', value: 5, description: 'Win 5 games' },
        [{ type: 'coins', amount: 500, description: 'Bonus coins' }],
        'medium'
      );

      expect(challenge.title).toBe('Win 5 Games');
      expect(challenge.type).toBe('daily');
    });

    it('should track challenge progress', () => {
      trackChallengeProgress(playerChallenge, 3, 5);
      expect(playerChallenge.progress).toBe(60);
      expect(playerChallenge.completed).toBe(false);

      trackChallengeProgress(playerChallenge, 5, 5);
      expect(playerChallenge.completed).toBe(true);
    });

    it('should create seasonal event', () => {
      const event = createSeasonalEvent(
        'Summer Festival',
        'Summer celebration event',
        'summer',
        new Date(),
        new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
        ['game1', 'game2'],
        [
          { rank: 1, amount: 1000, description: '1st place' },
          { rank: 2, amount: 500, description: '2nd place' },
        ]
      );

      expect(event.name).toBe('Summer Festival');
      expect(event.totalPrizePool).toBe(1500);
    });

    it('should update event leaderboard', () => {
      const event = createSeasonalEvent(
        'Test Event',
        'Test',
        'test',
        new Date(),
        new Date(),
        [],
        [{ rank: 1, amount: 1000, description: '1st' }]
      );

      updateEventLeaderboard(event, 1, 'player1', 1000);
      updateEventLeaderboard(event, 2, 'player2', 800);

      expect(event.leaderboard.rankings).toHaveLength(2);
      expect(event.leaderboard.rankings[0].rank).toBe(1);
    });

    it('should create battle pass', () => {
      const battlePass = createBattlePass('season1', 'premium', 100, [], new Date(), new Date(), 9.99);

      expect(battlePass.tier).toBe('premium');
      expect(battlePass.totalTiers).toBe(100);
    });

    it('should progress battle pass', () => {
      progressBattlePass(playerBattlePass, 500);
      expect(playerBattlePass.xp).toBe(500);

      progressBattlePass(playerBattlePass, 600);
      expect(playerBattlePass.currentTier).toBe(2);
    });

    it('should claim battle pass reward', () => {
      playerBattlePass.currentTier = 5;
      const claimed = claimBattlePassReward(playerBattlePass, 3);

      expect(claimed).toBe(true);
      expect(playerBattlePass.rewardsClaimed).toContain(3);
    });

    it('should calculate achievement progression', () => {
      const progression = calculateAchievementProgression(
        [playerAch],
        [PREDEFINED_ACHIEVEMENTS.first_win]
      );

      expect(progression.unlockedAchievements).toBe(1);
      expect(progression.completionPercentage).toBeGreaterThan(0);
    });

    it('should generate achievement leaderboard', () => {
      const playerProgression = [
        {
          playerId: 1,
          username: 'player1',
          progression: calculateAchievementProgression([playerAch], [PREDEFINED_ACHIEVEMENTS.first_win]),
        },
      ];

      const leaderboard = generateAchievementLeaderboard(playerProgression);

      expect(leaderboard).toHaveLength(1);
      expect(leaderboard[0].rank).toBe(1);
    });

    it('should create game season', () => {
      const season = createGameSeason('Season 1', 1, new Date(), new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), 'winter');

      expect(season.name).toBe('Season 1');
      expect(season.number).toBe(1);
    });
  });

  describe('Cross-System Integration', () => {
    it('should integrate admin actions with analytics', () => {
      const admin = createAdminUser('admin1', 'admin@example.com', 'admin');
      const churn = predictPlayerChurn(1, 'player1', 45, 30, 0.5, 100, 30);

      const log = createAuditLog(
        admin.id,
        admin.username,
        'update',
        'player',
        '1',
        { reason: 'High churn risk', riskScore: churn.churnRisk },
        '192.168.1.1',
        'Mozilla/5.0'
      );

      expect(log.details.riskScore).toBe(churn.churnRisk);
    });

    it('should integrate gamification with analytics', () => {
      const prediction = predictPlayerLTV(1, 'player1', 100, 5, 'slots', 60, 80, 2);
      const achievement = unlockAchievement(1, 'big_spender');

      expect(prediction.recommendations.length).toBeGreaterThan(0);
      expect(achievement.isCompleted).toBe(true);
    });

    it('should integrate admin moderation with gamification', () => {
      const moderation: PlayerModeration = {
        playerId: 1,
        username: 'player1',
        status: 'active',
        restrictions: [],
        warnings: 0,
        lastModeration: new Date(),
      };

      suspendPlayer(moderation, 'Fraud detected', 7);

      // Suspended players should not earn achievements
      expect(moderation.status).toBe('suspended');
    });
  });
});
