/**
 * Payment Analytics Service
 * Tracks payment performance, revenue, and conversion metrics
 */

export type Currency = 'USD' | 'EUR' | 'GBP' | 'CAD' | 'AUD' | 'JPY';
export type PaymentMethod = 'square' | 'paypal' | 'google_pay' | 'chime' | 'cash_app' | 'check' | 'bitcoin';

interface PaymentTransaction {
  id: string;
  method: PaymentMethod;
  currency: Currency;
  amount: number;
  usdAmount: number;
  status: 'completed' | 'failed' | 'pending';
  timestamp: Date;
  userId: string;
  gcAmount: number;
  scBonusAmount: number;
}

interface PaymentMethodStats {
  method: PaymentMethod;
  totalTransactions: number;
  successfulTransactions: number;
  failedTransactions: number;
  totalRevenue: number;
  averageTransaction: number;
  conversionRate: number;
  lastUpdated: Date;
}

interface CurrencyStats {
  currency: Currency;
  totalTransactions: number;
  totalRevenue: number;
  averageTransaction: number;
  conversionRate: number;
  lastUpdated: Date;
}

interface PaymentAnalytics {
  totalRevenue: number;
  totalTransactions: number;
  successRate: number;
  averageTransaction: number;
  methodStats: Map<PaymentMethod, PaymentMethodStats>;
  currencyStats: Map<Currency, CurrencyStats>;
  topPaymentMethods: PaymentMethodStats[];
  topCurrencies: CurrencyStats[];
  lastUpdated: Date;
}

class PaymentAnalyticsService {
  private transactions: PaymentTransaction[] = [];
  private analytics: PaymentAnalytics = {
    totalRevenue: 0,
    totalTransactions: 0,
    successRate: 0,
    averageTransaction: 0,
    methodStats: new Map(),
    currencyStats: new Map(),
    topPaymentMethods: [],
    topCurrencies: [],
    lastUpdated: new Date(),
  };

  /**
   * Record a payment transaction
   */
  recordTransaction(transaction: PaymentTransaction): void {
    this.transactions.push(transaction);
    this.updateAnalytics();
  }

  /**
   * Update analytics based on transactions
   */
  private updateAnalytics(): void {
    const methodStats = new Map<PaymentMethod, PaymentMethodStats>();
    const currencyStats = new Map<Currency, CurrencyStats>();

    let totalRevenue = 0;
    let totalTransactions = 0;
    let successfulTransactions = 0;

    // Process transactions
    this.transactions.forEach((tx) => {
      totalTransactions++;
      if (tx.status === 'completed') {
        successfulTransactions++;
        totalRevenue += tx.usdAmount;
      }

      // Method stats
      if (!methodStats.has(tx.method)) {
        methodStats.set(tx.method, {
          method: tx.method,
          totalTransactions: 0,
          successfulTransactions: 0,
          failedTransactions: 0,
          totalRevenue: 0,
          averageTransaction: 0,
          conversionRate: 0,
          lastUpdated: new Date(),
        });
      }

      const mStats = methodStats.get(tx.method)!;
      mStats.totalTransactions++;
      if (tx.status === 'completed') {
        mStats.successfulTransactions++;
        mStats.totalRevenue += tx.usdAmount;
      } else {
        mStats.failedTransactions++;
      }

      // Currency stats
      if (!currencyStats.has(tx.currency)) {
        currencyStats.set(tx.currency, {
          currency: tx.currency,
          totalTransactions: 0,
          totalRevenue: 0,
          averageTransaction: 0,
          conversionRate: 0,
          lastUpdated: new Date(),
        });
      }

      const cStats = currencyStats.get(tx.currency)!;
      cStats.totalTransactions++;
      if (tx.status === 'completed') {
        cStats.totalRevenue += tx.usdAmount;
      }
    });

    // Calculate rates and averages
    methodStats.forEach((stats) => {
      stats.conversionRate = (stats.successfulTransactions / stats.totalTransactions) * 100;
      stats.averageTransaction = stats.totalRevenue / stats.successfulTransactions || 0;
    });

    currencyStats.forEach((stats) => {
      stats.conversionRate = (stats.totalTransactions / totalTransactions) * 100;
      stats.averageTransaction = stats.totalRevenue / stats.totalTransactions || 0;
    });

    // Update main analytics
    this.analytics = {
      totalRevenue,
      totalTransactions,
      successRate: (successfulTransactions / totalTransactions) * 100 || 0,
      averageTransaction: totalRevenue / successfulTransactions || 0,
      methodStats,
      currencyStats,
      topPaymentMethods: Array.from(methodStats.values())
        .sort((a, b) => b.totalRevenue - a.totalRevenue)
        .slice(0, 5),
      topCurrencies: Array.from(currencyStats.values())
        .sort((a, b) => b.totalRevenue - a.totalRevenue)
        .slice(0, 5),
      lastUpdated: new Date(),
    };
  }

  /**
   * Get overall analytics
   */
  getAnalytics(): PaymentAnalytics {
    return this.analytics;
  }

  /**
   * Get payment method statistics
   */
  getMethodStats(method: PaymentMethod): PaymentMethodStats | undefined {
    return this.analytics.methodStats.get(method);
  }

  /**
   * Get currency statistics
   */
  getCurrencyStats(currency: Currency): CurrencyStats | undefined {
    return this.analytics.currencyStats.get(currency);
  }

  /**
   * Get revenue by date range
   */
  getRevenueByDateRange(startDate: Date, endDate: Date): number {
    return this.transactions
      .filter((tx) => tx.timestamp >= startDate && tx.timestamp <= endDate && tx.status === 'completed')
      .reduce((sum, tx) => sum + tx.usdAmount, 0);
  }

  /**
   * Get transaction count by date range
   */
  getTransactionCountByDateRange(startDate: Date, endDate: Date): number {
    return this.transactions.filter((tx) => tx.timestamp >= startDate && tx.timestamp <= endDate).length;
  }

  /**
   * Get success rate by date range
   */
  getSuccessRateByDateRange(startDate: Date, endDate: Date): number {
    const txs = this.transactions.filter((tx) => tx.timestamp >= startDate && tx.timestamp <= endDate);
    if (txs.length === 0) return 0;
    const successful = txs.filter((tx) => tx.status === 'completed').length;
    return (successful / txs.length) * 100;
  }

  /**
   * Get revenue by method
   */
  getRevenueByMethod(method: PaymentMethod): number {
    return this.transactions
      .filter((tx) => tx.method === method && tx.status === 'completed')
      .reduce((sum, tx) => sum + tx.usdAmount, 0);
  }

  /**
   * Get revenue by currency
   */
  getRevenueByCurrency(currency: Currency): number {
    return this.transactions
      .filter((tx) => tx.currency === currency && tx.status === 'completed')
      .reduce((sum, tx) => sum + tx.usdAmount, 0);
  }

  /**
   * Get top customers
   */
  getTopCustomers(limit: number = 10): Array<{ userId: string; totalSpent: number; transactionCount: number }> {
    const customerMap = new Map<string, { totalSpent: number; transactionCount: number }>();

    this.transactions
      .filter((tx) => tx.status === 'completed')
      .forEach((tx) => {
        if (!customerMap.has(tx.userId)) {
          customerMap.set(tx.userId, { totalSpent: 0, transactionCount: 0 });
        }
        const customer = customerMap.get(tx.userId)!;
        customer.totalSpent += tx.usdAmount;
        customer.transactionCount++;
      });

    return Array.from(customerMap.entries())
      .map(([userId, data]) => ({ userId, ...data }))
      .sort((a, b) => b.totalSpent - a.totalSpent)
      .slice(0, limit);
  }

  /**
   * Get conversion funnel
   */
  getConversionFunnel(): {
    initiated: number;
    completed: number;
    failed: number;
    conversionRate: number;
  } {
    const initiated = this.transactions.length;
    const completed = this.transactions.filter((tx) => tx.status === 'completed').length;
    const failed = this.transactions.filter((tx) => tx.status === 'failed').length;

    return {
      initiated,
      completed,
      failed,
      conversionRate: (completed / initiated) * 100 || 0,
    };
  }

  /**
   * Get daily revenue
   */
  getDailyRevenue(days: number = 30): Array<{ date: string; revenue: number; transactions: number }> {
    const dailyMap = new Map<string, { revenue: number; transactions: number }>();

    const now = new Date();
    for (let i = 0; i < days; i++) {
      const date = new Date(now);
      date.setDate(date.getDate() - i);
      const dateStr = date.toISOString().split('T')[0];
      dailyMap.set(dateStr, { revenue: 0, transactions: 0 });
    }

    this.transactions
      .filter((tx) => tx.status === 'completed')
      .forEach((tx) => {
        const dateStr = tx.timestamp.toISOString().split('T')[0];
        if (dailyMap.has(dateStr)) {
          const daily = dailyMap.get(dateStr)!;
          daily.revenue += tx.usdAmount;
          daily.transactions++;
        }
      });

    return Array.from(dailyMap.entries())
      .map(([date, data]) => ({ date, ...data }))
      .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
  }

  /**
   * Clear old transactions (for testing)
   */
  clearTransactions(): void {
    this.transactions = [];
    this.updateAnalytics();
  }
}

export const paymentAnalyticsService = new PaymentAnalyticsService();
