class ChitCalculator {
  /// Generic Chit Fund Calculator
  /// 
  /// Variables:
  /// C = chit value (₹)
  /// N = months
  /// S = C / N (subscription per month)
  /// F = commission per month (fixed value)
  /// k = month index (1…N)
  /// Dividend_k = dividend for month k
  
  static Map<String, dynamic> calculateChitFund({
    required double chitValue,
    required int months,
    required double commissionPerMonth,
    String commissionType = 'fixed',
    double? commissionRate,
    double? maxDividend,
  }) {
    // Calculate commission based on type
    double actualCommission;
    if (commissionType == 'percentage' && commissionRate != null) {
      actualCommission = (chitValue / months) * (commissionRate / 100);
    } else {
      actualCommission = commissionPerMonth;
    }
    
    // Core calculations
    final subscriptionPerMonth = chitValue / months;
    final installmentPerMonth = subscriptionPerMonth + actualCommission;
    
    // Calculate dividend schedule
    final dividendSchedule = _calculateDividendSchedule(
      months: months,
      maxDividend: maxDividend ?? (actualCommission * 2), // Default to 2x commission
    );
    
    // Calculate monthly breakdowns
    final monthlyBreakdowns = <Map<String, dynamic>>[];
    
    for (int k = 1; k <= months; k++) {
      final dividend = dividendSchedule[k - 1];
      final bid = chitValue - dividend;
      final netInstallmentNonWinner = installmentPerMonth - dividend;
      final netGainOnWin = bid - installmentPerMonth;
      
      monthlyBreakdowns.add({
        'month': k,
        'dividend': dividend,
        'bid': bid,
        'installment_per_month': installmentPerMonth,
        'net_installment_non_winner': netInstallmentNonWinner,
        'net_gain_on_win': netGainOnWin,
        'total_paid_if_winner': installmentPerMonth * k,
        'total_received_if_winner': bid,
        'net_gain_if_winner': bid - (installmentPerMonth * k),
      });
    }
    
    // Summary statistics
    final totalDividend = dividendSchedule.fold(0.0, (sum, dividend) => sum + dividend);
    final averageDividend = totalDividend / months;
    final firstMonthDividend = dividendSchedule.first;
    final lastMonthDividend = dividendSchedule.last;
    
    return {
      'chit_value': chitValue,
      'months': months,
      'subscription_per_month': subscriptionPerMonth,
      'commission_per_month': actualCommission,
      'commission_type': commissionType,
      'commission_rate': commissionRate,
      'installment_per_month': installmentPerMonth,
      'dividend_schedule': dividendSchedule,
      'monthly_breakdowns': monthlyBreakdowns,
      'summary': {
        'total_dividend': totalDividend,
        'average_dividend': averageDividend,
        'first_month_dividend': firstMonthDividend,
        'last_month_dividend': lastMonthDividend,
        'max_dividend': dividendSchedule.reduce((a, b) => a > b ? a : b),
        'min_dividend': dividendSchedule.reduce((a, b) => a < b ? a : b),
      },
    };
  }
  
  /// Calculate linear dividend schedule that sums to 0
  /// 
  /// Formula: Dividend_k = D_max - (k-1) * d
  /// Constraint: Σ_{k=1..N} Dividend_k = 0
  /// Therefore: d = 2*D_max / (N-1)
  static List<double> _calculateDividendSchedule({
    required int months,
    required double maxDividend,
  }) {
    if (months <= 1) return [0.0];
    
    final step = (2 * maxDividend) / (months - 1);
    final dividends = <double>[];
    
    for (int k = 1; k <= months; k++) {
      final dividend = maxDividend - ((k - 1) * step);
      dividends.add(dividend);
    }
    
    return dividends;
  }
  
  /// Calculate advantage structure for early vs late winners
  static Map<String, dynamic> calculateAdvantageStructure({
    required double chitValue,
    required int months,
    required double commissionPerMonth,
    double? maxDividend,
  }) {
    final calculation = calculateChitFund(
      chitValue: chitValue,
      months: months,
      commissionPerMonth: commissionPerMonth,
      maxDividend: maxDividend,
    );
    
    final monthlyBreakdowns = calculation['monthly_breakdowns'] as List<Map<String, dynamic>>;
    
    // First month winner
    final firstMonth = monthlyBreakdowns.first;
    
    // Last month winner
    final lastMonth = monthlyBreakdowns.last;
    
    return {
      'first_month_winner': {
        'month': firstMonth['month'],
        'dividend_others_get': firstMonth['dividend'],
        'bid_amount': firstMonth['bid'],
        'installment_paid': firstMonth['installment_per_month'],
        'net_gain': firstMonth['net_gain_on_win'],
        'total_paid': firstMonth['total_paid_if_winner'],
        'total_received': firstMonth['total_received_if_winner'],
        'net_gain_total': firstMonth['net_gain_if_winner'],
      },
      'last_month_winner': {
        'month': lastMonth['month'],
        'dividend_others_pay': lastMonth['dividend'] * -1, // Convert to positive for display
        'bid_amount': lastMonth['bid'],
        'installment_paid': lastMonth['installment_per_month'],
        'net_gain': lastMonth['net_gain_on_win'],
        'total_paid': lastMonth['total_paid_if_winner'],
        'total_received': lastMonth['total_received_if_winner'],
        'net_gain_total': lastMonth['net_gain_if_winner'],
      },
      'commission_per_month': commissionPerMonth,
      'subscription_per_month': calculation['subscription_per_month'],
      'installment_per_month': calculation['installment_per_month'],
    };
  }
  
  /// Calculate dividend schedule for different chit values
  /// Useful for comparing different chit fund sizes
  static Map<String, dynamic> calculateScaledDividendSchedule({
    required double baseChitValue,
    required double baseMaxDividend,
    required int months,
    required double commissionPerMonth,
    List<double>? scaleFactors,
  }) {
    scaleFactors ??= [0.5, 1.0, 1.5, 2.0]; // Default scale factors
    
    final schedules = <Map<String, dynamic>>[];
    
    for (final scaleFactor in scaleFactors) {
      final chitValue = baseChitValue * scaleFactor;
      final maxDividend = baseMaxDividend * scaleFactor;
      
      final calculation = calculateChitFund(
        chitValue: chitValue,
        months: months,
        commissionPerMonth: commissionPerMonth,
        maxDividend: maxDividend,
      );
      
      schedules.add({
        'scale_factor': scaleFactor,
        'chit_value': chitValue,
        'max_dividend': maxDividend,
        'dividend_schedule': calculation['dividend_schedule'],
        'first_month_dividend': calculation['summary']['first_month_dividend'],
        'last_month_dividend': calculation['summary']['last_month_dividend'],
        'installment_per_month': calculation['installment_per_month'],
      });
    }
    
    return {
      'base_chit_value': baseChitValue,
      'base_max_dividend': baseMaxDividend,
      'months': months,
      'commission_per_month': commissionPerMonth,
      'schedules': schedules,
    };
  }
  
  /// Validate chit fund parameters
  static Map<String, dynamic> validateParameters({
    required double chitValue,
    required int months,
    required double commissionPerMonth,
    double? maxDividend,
  }) {
    final errors = <String>[];
    final warnings = <String>[];
    
    // Validation rules
    if (chitValue <= 0) {
      errors.add('Chit value must be positive');
    }
    
    if (months <= 0) {
      errors.add('Number of months must be positive');
    }
    
    if (commissionPerMonth < 0) {
      errors.add('Commission per month cannot be negative');
    }
    
    if (commissionPerMonth > chitValue * 0.1) {
      warnings.add('Commission is more than 10% of chit value');
    }
    
    if (maxDividend != null && maxDividend <= 0) {
      errors.add('Maximum dividend must be positive');
    }
    
    // Business logic validation
    if (months > 60) {
      warnings.add('Very long duration (${months} months) may affect member commitment');
    }
    
    if (chitValue < 10000) {
      warnings.add('Very small chit value may not be attractive to members');
    }
    
    if (chitValue > 1000000) {
      warnings.add('Very large chit value may be difficult to manage');
    }
    
    return {
      'isValid': errors.isEmpty,
      'errors': errors,
      'warnings': warnings,
    };
  }
}
