/**
 * Payment Analytics System
 * Tracks and analyzes payment transactions, revenue trends, and player spending patterns
 */

export interface PaymentMetrics {
  totalRevenue: number;
  totalTransactions: number;
  averageTransactionValue: number;
  medianTransactionValue: number;
  minTransactionValue: number;
  maxTransactionValue: number;
  standardDeviation: number;
}

export interface RevenueBreakdown {
  byPaymentMethod: Record<string, { count: number; amount: number; percentage: number }>;
  byPackage: Record<string, { count: number; amount: number; percentage: number }>;
  byHour: Record<number, { count: number; amount: number }>;
  byDay: Record<string, { count: number; amount: number }>;
  byCountry: Record<string, { count: number; amount: number; percentage: number }>;
}

export interface PlayerSpendingAnalysis {
  totalPlayers: number;
  spendingPlayers: number;
  averageSpendPerPlayer: number;
  medianSpendPerPlayer: number;
  topSpenders: Array<{
    playerId: number;
    playerName: string;
    totalSpent: number;
    transactionCount: number;
    averageTransaction: number;
  }>;
  spendingDistribution: {
    tier1: number; // $0-$10
    tier2: number; // $10-$50
    tier3: number; // $50-$100
    tier4: number; // $100-$500
    tier5: number; // $500+
  };
}

export interface ConversionMetrics {
  totalVisitors: number;
  purchasingVisitors: number;
  conversionRate: number; // percentage
  repeatPurchaseRate: number; // percentage
  averageOrdersPerPlayer: number;
  customerLifetimeValue: number;
  churnRate: number; // percentage
}

export interface TrendAnalysis {
  period: 'daily' | 'weekly' | 'monthly';
  startDate: Date;
  endDate: Date;
  trend: 'up' | 'down' | 'stable';
  percentageChange: number;
  dataPoints: Array<{
    date: Date;
    revenue: number;
    transactions: number;
    averageValue: number;
  }>;
}

export interface AnomalyDetection {
  anomalies: Array<{
    type: 'spike' | 'drop' | 'unusual_pattern';
    severity: 'low' | 'medium' | 'high';
    date: Date;
    description: string;
    expectedValue: number;
    actualValue: number;
    deviation: number; // percentage
  }>;
  alerts: Array<{
    id: string;
    type: 'high_volume' | 'low_volume' | 'high_value' | 'fraud_risk';
    severity: 'low' | 'medium' | 'high' | 'critical';
    message: string;
    timestamp: Date;
    acknowledged: boolean;
  }>;
}

export interface PaymentAnalyticsReport {
  period: 'daily' | 'weekly' | 'monthly';
  startDate: Date;
  endDate: Date;
  metrics: PaymentMetrics;
  breakdown: RevenueBreakdown;
  spending: PlayerSpendingAnalysis;
  conversion: ConversionMetrics;
  trends: TrendAnalysis;
  anomalies: AnomalyDetection;
}

/**
 * Calculate payment metrics
 */
export function calculatePaymentMetrics(amounts: number[]): PaymentMetrics {
  if (amounts.length === 0) {
    return {
      totalRevenue: 0,
      totalTransactions: 0,
      averageTransactionValue: 0,
      medianTransactionValue: 0,
      minTransactionValue: 0,
      maxTransactionValue: 0,
      standardDeviation: 0,
    };
  }

  const totalRevenue = amounts.reduce((sum, a) => sum + a, 0);
  const totalTransactions = amounts.length;
  const averageTransactionValue = totalRevenue / totalTransactions;

  // Calculate median
  const sorted = [...amounts].sort((a, b) => a - b);
  const medianTransactionValue =
    totalTransactions % 2 === 0
      ? (sorted[totalTransactions / 2 - 1] + sorted[totalTransactions / 2]) / 2
      : sorted[Math.floor(totalTransactions / 2)];

  const minTransactionValue = Math.min(...amounts);
  const maxTransactionValue = Math.max(...amounts);

  // Calculate standard deviation
  const variance =
    amounts.reduce((sum, a) => sum + Math.pow(a - averageTransactionValue, 2), 0) /
    totalTransactions;
  const standardDeviation = Math.sqrt(variance);

  return {
    totalRevenue,
    totalTransactions,
    averageTransactionValue,
    medianTransactionValue,
    minTransactionValue,
    maxTransactionValue,
    standardDeviation,
  };
}

/**
 * Analyze spending by payment method
 */
export function analyzeSpendingByMethod(
  transactions: Array<{ method: string; amount: number }>
): Record<string, { count: number; amount: number; percentage: number }> {
  const totalAmount = transactions.reduce((sum, t) => sum + t.amount, 0);
  const breakdown: Record<string, { count: number; amount: number; percentage: number }> = {};

  transactions.forEach((t) => {
    if (!breakdown[t.method]) {
      breakdown[t.method] = { count: 0, amount: 0, percentage: 0 };
    }
    breakdown[t.method].count++;
    breakdown[t.method].amount += t.amount;
  });

  // Calculate percentages
  Object.keys(breakdown).forEach((method) => {
    breakdown[method].percentage = (breakdown[method].amount / totalAmount) * 100;
  });

  return breakdown;
}

/**
 * Analyze player spending distribution
 */
export function analyzePlayerSpendingDistribution(
  playerSpending: Array<{ playerId: number; totalSpent: number }>
): {
  tier1: number;
  tier2: number;
  tier3: number;
  tier4: number;
  tier5: number;
} {
  const distribution = {
    tier1: 0, // $0-$10
    tier2: 0, // $10-$50
    tier3: 0, // $50-$100
    tier4: 0, // $100-$500
    tier5: 0, // $500+
  };

  playerSpending.forEach(({ totalSpent }) => {
    if (totalSpent < 10) distribution.tier1++;
    else if (totalSpent < 50) distribution.tier2++;
    else if (totalSpent < 100) distribution.tier3++;
    else if (totalSpent < 500) distribution.tier4++;
    else distribution.tier5++;
  });

  return distribution;
}

/**
 * Detect anomalies in payment data
 */
export function detectAnomalies(
  dataPoints: Array<{ date: Date; revenue: number; transactions: number }>,
  threshold: number = 2 // standard deviations
): AnomalyDetection {
  const anomalies: AnomalyDetection['anomalies'] = [];
  const alerts: AnomalyDetection['alerts'] = [];

  // Calculate statistics
  const revenues = dataPoints.map((d) => d.revenue);
  const metrics = calculatePaymentMetrics(revenues);

  // Detect revenue anomalies
  dataPoints.forEach((point) => {
    const deviation = Math.abs(point.revenue - metrics.averageTransactionValue);
    const deviationPercent = (deviation / metrics.averageTransactionValue) * 100;

    if (deviation > metrics.standardDeviation * threshold) {
      const type = point.revenue > metrics.averageTransactionValue ? 'spike' : 'drop';
      const severity =
        deviationPercent > 50 ? 'high' : deviationPercent > 25 ? 'medium' : 'low';

      anomalies.push({
        type,
        severity,
        date: point.date,
        description: `Revenue ${type} detected on ${point.date.toDateString()}`,
        expectedValue: metrics.averageTransactionValue,
        actualValue: point.revenue,
        deviation: deviationPercent,
      });

      // Generate alert for high severity
      if (severity === 'high') {
        alerts.push({
          id: `alert_${point.date.getTime()}`,
          type: type === 'spike' ? 'high_volume' : 'low_volume',
          severity: 'high',
          message: `Revenue ${type} of ${deviationPercent.toFixed(1)}% detected`,
          timestamp: new Date(),
          acknowledged: false,
        });
      }
    }
  });

  return { anomalies, alerts };
}

/**
 * Calculate conversion metrics
 */
export function calculateConversionMetrics(
  totalVisitors: number,
  purchasingPlayers: number,
  totalTransactions: number,
  totalRevenue: number,
  repeatingPlayers: number
): ConversionMetrics {
  const conversionRate = totalVisitors > 0 ? (purchasingPlayers / totalVisitors) * 100 : 0;
  const repeatPurchaseRate =
    purchasingPlayers > 0 ? (repeatingPlayers / purchasingPlayers) * 100 : 0;
  const averageOrdersPerPlayer =
    purchasingPlayers > 0 ? totalTransactions / purchasingPlayers : 0;
  const customerLifetimeValue =
    purchasingPlayers > 0 ? totalRevenue / purchasingPlayers : 0;
  const churnRate = 100 - repeatPurchaseRate;

  return {
    totalVisitors,
    purchasingVisitors: purchasingPlayers,
    conversionRate,
    repeatPurchaseRate,
    averageOrdersPerPlayer,
    customerLifetimeValue,
    churnRate,
  };
}

/**
 * Analyze trends
 */
export function analyzeTrends(
  dataPoints: Array<{ date: Date; revenue: number; transactions: number }>
): TrendAnalysis {
  if (dataPoints.length < 2) {
    return {
      period: 'daily',
      startDate: new Date(),
      endDate: new Date(),
      trend: 'stable',
      percentageChange: 0,
      dataPoints: [],
    };
  }

  const firstHalf = dataPoints.slice(0, Math.floor(dataPoints.length / 2));
  const secondHalf = dataPoints.slice(Math.floor(dataPoints.length / 2));

  const firstHalfRevenue = firstHalf.reduce((sum, d) => sum + d.revenue, 0);
  const secondHalfRevenue = secondHalf.reduce((sum, d) => sum + d.revenue, 0);

  const percentageChange =
    firstHalfRevenue > 0 ? ((secondHalfRevenue - firstHalfRevenue) / firstHalfRevenue) * 100 : 0;

  let trend: 'up' | 'down' | 'stable' = 'stable';
  if (percentageChange > 5) trend = 'up';
  else if (percentageChange < -5) trend = 'down';

  return {
    period: 'daily',
    startDate: dataPoints[0].date,
    endDate: dataPoints[dataPoints.length - 1].date,
    trend,
    percentageChange,
    dataPoints,
  };
}

/**
 * Generate comprehensive analytics report
 */
export function generatePaymentAnalyticsReport(
  period: 'daily' | 'weekly' | 'monthly',
  startDate: Date,
  endDate: Date,
  transactions: Array<{
    amount: number;
    method: string;
    packageId: string;
    playerId: number;
    date: Date;
    country?: string;
  }>,
  playerData: Array<{
    playerId: number;
    playerName: string;
    totalSpent: number;
    transactionCount: number;
    isRepeating: boolean;
  }>
): PaymentAnalyticsReport {
  // Calculate metrics
  const amounts = transactions.map((t) => t.amount);
  const metrics = calculatePaymentMetrics(amounts);

  // Revenue breakdown
  const byMethod = analyzeSpendingByMethod(
    transactions.map((t) => ({ method: t.method, amount: t.amount }))
  );

  const byPackage: Record<string, { count: number; amount: number; percentage: number }> = {};
  const totalAmount = metrics.totalRevenue;
  transactions.forEach((t) => {
    if (!byPackage[t.packageId]) {
      byPackage[t.packageId] = { count: 0, amount: 0, percentage: 0 };
    }
    byPackage[t.packageId].count++;
    byPackage[t.packageId].amount += t.amount;
  });

  Object.keys(byPackage).forEach((pkg) => {
    byPackage[pkg].percentage = (byPackage[pkg].amount / totalAmount) * 100;
  });

  // Hourly breakdown
  const byHour: Record<number, { count: number; amount: number }> = {};
  for (let i = 0; i < 24; i++) {
    byHour[i] = { count: 0, amount: 0 };
  }
  transactions.forEach((t) => {
    const hour = new Date(t.date).getHours();
    byHour[hour].count++;
    byHour[hour].amount += t.amount;
  });

  // Player spending analysis
  const topSpenders = playerData
    .sort((a, b) => b.totalSpent - a.totalSpent)
    .slice(0, 10)
    .map((p) => ({
      playerId: p.playerId,
      playerName: p.playerName,
      totalSpent: p.totalSpent,
      transactionCount: p.transactionCount,
      averageTransaction: p.transactionCount > 0 ? p.totalSpent / p.transactionCount : 0,
    }));

  const spendingDistribution = analyzePlayerSpendingDistribution(playerData);

  // Conversion metrics
  const repeatingPlayers = playerData.filter((p) => p.isRepeating).length;
  const conversionMetrics = calculateConversionMetrics(
    1000, // Placeholder for total visitors
    playerData.length,
    transactions.length,
    metrics.totalRevenue,
    repeatingPlayers
  );

  // Trends
  const dailyData = transactions.reduce(
    (acc, t) => {
      const dateKey = t.date.toDateString();
      if (!acc[dateKey]) {
        acc[dateKey] = { date: t.date, revenue: 0, transactions: 0 };
      }
      acc[dateKey].revenue += t.amount;
      acc[dateKey].transactions++;
      return acc;
    },
    {} as Record<string, { date: Date; revenue: number; transactions: number }>
  );

  const trends = analyzeTrends(Object.values(dailyData));

  // Anomaly detection
  const anomalies = detectAnomalies(Object.values(dailyData));

  return {
    period,
    startDate,
    endDate,
    metrics,
    breakdown: {
      byPaymentMethod: byMethod,
      byPackage,
      byHour,
      byDay: dailyData,
      byCountry: {}, // Placeholder
    },
    spending: {
      totalPlayers: playerData.length,
      spendingPlayers: playerData.length,
      averageSpendPerPlayer: metrics.totalRevenue / playerData.length,
      medianSpendPerPlayer: metrics.medianTransactionValue,
      topSpenders,
      spendingDistribution,
    },
    conversion: conversionMetrics,
    trends,
    anomalies,
  };
}
