/**
 * Advanced Analytics with Machine Learning
 * Cohort analysis, player lifetime value prediction, and churn forecasting
 */

export interface PlayerCohort {
  cohortId: string;
  cohortDate: Date;
  cohortSize: number;
  acquisitionChannel: string;
  retention: {
    day1: number;
    day7: number;
    day30: number;
    day90: number;
  };
  revenue: {
    day1: number;
    day7: number;
    day30: number;
    day90: number;
  };
  ltv: number; // Lifetime Value
}

export interface PlayerLTVPrediction {
  playerId: number;
  username: string;
  predictedLTV: number;
  confidence: number; // 0-100
  factors: {
    depositAmount: number;
    playFrequency: number;
    gamePreference: string;
    sessionDuration: number;
    bonusUtilization: number;
    referralActivity: number;
  };
  segmentId: string;
  recommendations: string[];
}

export interface ChurnPrediction {
  playerId: number;
  username: string;
  churnRisk: number; // 0-100
  daysUntilChurn: number;
  riskFactors: string[];
  retentionStrategies: string[];
  priority: 'high' | 'medium' | 'low';
}

export interface PlayerSegment {
  id: string;
  name: string;
  description: string;
  criteria: Record<string, any>;
  playerCount: number;
  averageLTV: number;
  churnRate: number;
  engagementScore: number;
}

export interface PredictiveModel {
  modelId: string;
  name: string;
  type: 'ltv' | 'churn' | 'engagement' | 'fraud';
  version: number;
  accuracy: number; // 0-100
  precision: number; // 0-100
  recall: number; // 0-100
  lastTrained: Date;
  nextRetraining: Date;
}

/**
 * Create player cohort
 */
export function createPlayerCohort(
  cohortDate: Date,
  cohortSize: number,
  acquisitionChannel: string
): PlayerCohort {
  return {
    cohortId: `cohort_${cohortDate.toISOString().split('T')[0]}`,
    cohortDate,
    cohortSize,
    acquisitionChannel,
    retention: {
      day1: 0,
      day7: 0,
      day30: 0,
      day90: 0,
    },
    revenue: {
      day1: 0,
      day7: 0,
      day30: 0,
      day90: 0,
    },
    ltv: 0,
  };
}

/**
 * Update cohort retention
 */
export function updateCohortRetention(
  cohort: PlayerCohort,
  daysSinceAcquisition: number,
  retainedPlayers: number
): void {
  const retentionRate = (retainedPlayers / cohort.cohortSize) * 100;

  if (daysSinceAcquisition <= 1) {
    cohort.retention.day1 = retentionRate;
  } else if (daysSinceAcquisition <= 7) {
    cohort.retention.day7 = retentionRate;
  } else if (daysSinceAcquisition <= 30) {
    cohort.retention.day30 = retentionRate;
  } else if (daysSinceAcquisition <= 90) {
    cohort.retention.day90 = retentionRate;
  }
}

/**
 * Update cohort revenue
 */
export function updateCohortRevenue(
  cohort: PlayerCohort,
  daysSinceAcquisition: number,
  revenue: number
): void {
  if (daysSinceAcquisition <= 1) {
    cohort.revenue.day1 = revenue;
  } else if (daysSinceAcquisition <= 7) {
    cohort.revenue.day7 = revenue;
  } else if (daysSinceAcquisition <= 30) {
    cohort.revenue.day30 = revenue;
  } else if (daysSinceAcquisition <= 90) {
    cohort.revenue.day90 = revenue;
  }

  cohort.ltv = cohort.revenue.day90; // Simplified LTV calculation
}

/**
 * Predict player LTV using ML model
 */
export function predictPlayerLTV(
  playerId: number,
  username: string,
  depositAmount: number,
  playFrequency: number, // plays per day
  gamePreference: string,
  sessionDuration: number, // minutes
  bonusUtilization: number, // 0-100
  referralActivity: number // referrals made
): PlayerLTVPrediction {
  // Simplified ML model (in production, would use actual ML library)
  const baseScore = depositAmount * 10;
  const frequencyScore = playFrequency * 50;
  const sessionScore = sessionDuration * 2;
  const bonusScore = bonusUtilization * 5;
  const referralScore = referralActivity * 100;

  const predictedLTV = baseScore + frequencyScore + sessionScore + bonusScore + referralScore;
  const confidence = Math.min(100, 60 + (playFrequency * 5)); // Higher confidence with more data

  let segmentId = 'low_value';
  if (predictedLTV > 5000) {
    segmentId = 'high_value';
  } else if (predictedLTV > 1000) {
    segmentId = 'medium_value';
  }

  const recommendations: string[] = [];
  if (depositAmount < 50) {
    recommendations.push('Offer first deposit bonus');
  }
  if (playFrequency < 2) {
    recommendations.push('Send engagement emails');
  }
  if (referralActivity === 0) {
    recommendations.push('Promote referral program');
  }

  return {
    playerId,
    username,
    predictedLTV,
    confidence,
    factors: {
      depositAmount,
      playFrequency,
      gamePreference,
      sessionDuration,
      bonusUtilization,
      referralActivity,
    },
    segmentId,
    recommendations,
  };
}

/**
 * Predict player churn
 */
export function predictPlayerChurn(
  playerId: number,
  username: string,
  daysSinceLastLogin: number,
  daysSinceLastDeposit: number,
  averageSessionFrequency: number, // per week
  recentLosses: number,
  accountAge: number // days
): ChurnPrediction {
  let churnRisk = 0;
  const riskFactors: string[] = [];

  // Days since last login
  if (daysSinceLastLogin > 30) {
    churnRisk += 40;
    riskFactors.push('No login in 30+ days');
  } else if (daysSinceLastLogin > 14) {
    churnRisk += 25;
    riskFactors.push('No login in 14+ days');
  } else if (daysSinceLastLogin > 7) {
    churnRisk += 15;
    riskFactors.push('No login in 7+ days');
  }

  // Days since last deposit
  if (daysSinceLastDeposit > 60) {
    churnRisk += 30;
    riskFactors.push('No deposit in 60+ days');
  } else if (daysSinceLastDeposit > 30) {
    churnRisk += 20;
    riskFactors.push('No deposit in 30+ days');
  }

  // Session frequency decline
  if (averageSessionFrequency < 1) {
    churnRisk += 20;
    riskFactors.push('Low session frequency');
  }

  // Recent losses
  if (recentLosses > 500) {
    churnRisk += 15;
    riskFactors.push('Recent significant losses');
  }

  // Account age (new accounts have higher churn)
  if (accountAge < 30) {
    churnRisk += 10;
    riskFactors.push('New account (high natural churn)');
  }

  const daysUntilChurn = Math.max(1, 90 - daysSinceLastLogin);
  const priority = churnRisk > 70 ? 'high' : churnRisk > 40 ? 'medium' : 'low';

  const retentionStrategies: string[] = [];
  if (churnRisk > 70) {
    retentionStrategies.push('Send VIP retention offer');
    retentionStrategies.push('Offer free bonus credits');
    retentionStrategies.push('Personal account manager outreach');
  } else if (churnRisk > 40) {
    retentionStrategies.push('Send personalized game recommendations');
    retentionStrategies.push('Offer deposit bonus');
    retentionStrategies.push('Invite to tournament');
  } else {
    retentionStrategies.push('Send weekly newsletter');
    retentionStrategies.push('Highlight new games');
  }

  return {
    playerId,
    username,
    churnRisk: Math.min(100, churnRisk),
    daysUntilChurn,
    riskFactors,
    retentionStrategies,
    priority,
  };
}

/**
 * Create player segment
 */
export function createPlayerSegment(
  name: string,
  description: string,
  criteria: Record<string, any>,
  playerCount: number,
  averageLTV: number,
  churnRate: number
): PlayerSegment {
  const engagementScore = Math.max(0, 100 - churnRate - (averageLTV > 1000 ? 0 : 20));

  return {
    id: `segment_${name.toLowerCase().replace(/\s+/g, '_')}`,
    name,
    description,
    criteria,
    playerCount,
    averageLTV,
    churnRate,
    engagementScore,
  };
}

/**
 * Segment players based on LTV predictions
 */
export function segmentPlayersByLTV(
  predictions: PlayerLTVPrediction[]
): Record<string, PlayerLTVPrediction[]> {
  const segments: Record<string, PlayerLTVPrediction[]> = {
    high_value: [],
    medium_value: [],
    low_value: [],
  };

  predictions.forEach((pred) => {
    segments[pred.segmentId].push(pred);
  });

  return segments;
}

/**
 * Identify at-risk players
 */
export function identifyAtRiskPlayers(
  churnPredictions: ChurnPrediction[],
  threshold: number = 70
): ChurnPrediction[] {
  return churnPredictions.filter((pred) => pred.churnRisk >= threshold);
}

/**
 * Predictive model performance
 */
export function createPredictiveModel(
  name: string,
  type: 'ltv' | 'churn' | 'engagement' | 'fraud',
  accuracy: number,
  precision: number,
  recall: number
): PredictiveModel {
  return {
    modelId: `model_${type}_${Date.now()}`,
    name,
    type,
    version: 1,
    accuracy,
    precision,
    recall,
    lastTrained: new Date(),
    nextRetraining: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
  };
}

/**
 * Calculate model F1 score
 */
export function calculateF1Score(precision: number, recall: number): number {
  if (precision + recall === 0) return 0;
  return (2 * precision * recall) / (precision + recall);
}

/**
 * Engagement prediction
 */
export interface EngagementPrediction {
  playerId: number;
  username: string;
  engagementScore: number; // 0-100
  predictedDailyActiveProb: number; // 0-1
  predictedMonthlySpend: number;
  gamePreferences: Array<{ gameId: string; probability: number }>;
  optimalNotificationTime: string;
  recommendedOffers: string[];
}

export function predictPlayerEngagement(
  playerId: number,
  username: string,
  recentSessions: number,
  averageSessionValue: number,
  favoriteGames: string[],
  timezone: string
): EngagementPrediction {
  const engagementScore = Math.min(100, recentSessions * 10 + (averageSessionValue / 10));
  const predictedDailyActiveProb = Math.min(1, recentSessions / 30);
  const predictedMonthlySpend = averageSessionValue * Math.max(1, recentSessions / 7);

  // Optimal notification time (peak engagement hours)
  const optimalTimes: Record<string, string> = {
    'America/New_York': '19:00',
    'America/Los_Angeles': '18:00',
    'Europe/London': '20:00',
    'Europe/Paris': '21:00',
    'Asia/Tokyo': '22:00',
  };

  const optimalNotificationTime = optimalTimes[timezone] || '20:00';

  return {
    playerId,
    username,
    engagementScore,
    predictedDailyActiveProb,
    predictedMonthlySpend,
    gamePreferences: favoriteGames.map((game, idx) => ({
      gameId: game,
      probability: Math.max(0.3, 1 - idx * 0.2),
    })),
    optimalNotificationTime,
    recommendedOffers: [
      'Personalized bonus for favorite game',
      'Tournament invitation',
      'VIP tier upgrade offer',
    ],
  };
}

/**
 * Cohort analysis report
 */
export interface CohortAnalysisReport {
  cohorts: PlayerCohort[];
  averageRetention: {
    day1: number;
    day7: number;
    day30: number;
    day90: number;
  };
  averageLTV: number;
  bestPerformingCohort: PlayerCohort;
  worstPerformingCohort: PlayerCohort;
  trends: string[];
}

export function generateCohortAnalysisReport(cohorts: PlayerCohort[]): CohortAnalysisReport {
  if (cohorts.length === 0) {
    throw new Error('No cohorts provided');
  }

  const avgRetention = {
    day1: cohorts.reduce((sum, c) => sum + c.retention.day1, 0) / cohorts.length,
    day7: cohorts.reduce((sum, c) => sum + c.retention.day7, 0) / cohorts.length,
    day30: cohorts.reduce((sum, c) => sum + c.retention.day30, 0) / cohorts.length,
    day90: cohorts.reduce((sum, c) => sum + c.retention.day90, 0) / cohorts.length,
  };

  const avgLTV = cohorts.reduce((sum, c) => sum + c.ltv, 0) / cohorts.length;

  const bestCohort = cohorts.reduce((best, current) =>
    current.ltv > best.ltv ? current : best
  );

  const worstCohort = cohorts.reduce((worst, current) =>
    current.ltv < worst.ltv ? current : worst
  );

  const trends: string[] = [];
  if (avgRetention.day30 < 20) {
    trends.push('Low 30-day retention - consider onboarding improvements');
  }
  if (avgLTV < 500) {
    trends.push('Low average LTV - review monetization strategy');
  }

  return {
    cohorts,
    averageRetention: avgRetention,
    averageLTV: avgLTV,
    bestPerformingCohort: bestCohort,
    worstPerformingCohort: worstCohort,
    trends,
  };
}
