/**
 * Payment Reconciliation System
 * Compare platform records with payment provider statements
 */

export interface PaymentRecord {
  id: string;
  provider: string;
  transactionId: string;
  amount: number;
  currency: string;
  status: string;
  timestamp: Date;
  userId: number;
}

export interface ProviderStatement {
  id: string;
  provider: string;
  transactionId: string;
  amount: number;
  currency: string;
  status: string;
  timestamp: Date;
  fees: number;
  netAmount: number;
}

export interface ReconciliationResult {
  id: string;
  date: Date;
  provider: string;
  totalRecords: number;
  totalMatched: number;
  totalMissing: number;
  totalExtra: number;
  totalDiscrepancies: number;
  totalAmount: number;
  discrepancies: DiscrepancyRecord[];
  status: 'completed' | 'failed' | 'pending';
}

export interface DiscrepancyRecord {
  id: string;
  type: 'missing_in_platform' | 'missing_in_provider' | 'amount_mismatch' | 'status_mismatch';
  platformRecord?: PaymentRecord;
  providerRecord?: ProviderStatement;
  difference?: number;
  severity: 'low' | 'medium' | 'high' | 'critical';
  resolved: boolean;
  resolution?: string;
}

/**
 * Reconcile platform records with provider statement
 */
export function reconcilePayments(
  platformRecords: PaymentRecord[],
  providerStatements: ProviderStatement[]
): ReconciliationResult {
  const discrepancies: DiscrepancyRecord[] = [];
  const matched = new Set<string>();

  // Check for matches and discrepancies
  for (const platform of platformRecords) {
    const provider = providerStatements.find(
      p => p.transactionId === platform.transactionId && p.provider === platform.provider
    );

    if (!provider) {
      // Missing in provider
      discrepancies.push({
        id: `DISC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
        type: 'missing_in_provider',
        platformRecord: platform,
        severity: 'high',
        resolved: false,
      });
    } else {
      matched.add(provider.id);

      // Check for amount mismatch
      if (Math.abs(platform.amount - provider.amount) > 0.01) {
        discrepancies.push({
          id: `DISC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
          type: 'amount_mismatch',
          platformRecord: platform,
          providerRecord: provider,
          difference: provider.amount - platform.amount,
          severity: 'high',
          resolved: false,
        });
      }

      // Check for status mismatch
      if (platform.status !== provider.status) {
        discrepancies.push({
          id: `DISC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
          type: 'status_mismatch',
          platformRecord: platform,
          providerRecord: provider,
          severity: 'medium',
          resolved: false,
        });
      }
    }
  }

  // Check for extra in provider (not in platform)
  for (const provider of providerStatements) {
    if (!matched.has(provider.id)) {
      discrepancies.push({
        id: `DISC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
        type: 'missing_in_platform',
        providerRecord: provider,
        severity: 'critical',
        resolved: false,
      });
    }
  }

  const totalAmount = platformRecords.reduce((sum, r) => sum + r.amount, 0);
  const provider = platformRecords[0]?.provider || 'unknown';

  return {
    id: `RECON-${Date.now()}`,
    date: new Date(),
    provider,
    totalRecords: platformRecords.length,
    totalMatched: matched.size,
    totalMissing: discrepancies.filter(d => d.type === 'missing_in_provider').length,
    totalExtra: discrepancies.filter(d => d.type === 'missing_in_platform').length,
    totalDiscrepancies: discrepancies.length,
    totalAmount,
    discrepancies,
    status: discrepancies.length === 0 ? 'completed' : 'completed',
  };
}

/**
 * Generate reconciliation report
 */
export function generateReconciliationReport(result: ReconciliationResult): string {
  const criticalDiscrepancies = result.discrepancies.filter(d => d.severity === 'critical');
  const highDiscrepancies = result.discrepancies.filter(d => d.severity === 'high');
  const mediumDiscrepancies = result.discrepancies.filter(d => d.severity === 'medium');

  return `
PAYMENT RECONCILIATION REPORT
Provider: ${result.provider}
Date: ${result.date.toISOString()}
Report ID: ${result.id}

SUMMARY
-------
Total Records: ${result.totalRecords}
Total Matched: ${result.totalMatched}
Total Discrepancies: ${result.totalDiscrepancies}
Total Amount: $${result.totalAmount.toFixed(2)}
Match Rate: ${((result.totalMatched / result.totalRecords) * 100).toFixed(1)}%

DISCREPANCY BREAKDOWN
---------------------
Critical Issues: ${criticalDiscrepancies.length}
High Priority: ${highDiscrepancies.length}
Medium Priority: ${mediumDiscrepancies.length}
Low Priority: ${result.discrepancies.filter(d => d.severity === 'low').length}

CRITICAL ISSUES
---------------
${criticalDiscrepancies.map(d => `- ${d.type}: ${d.providerRecord?.transactionId || 'N/A'} ($${d.providerRecord?.amount || 0})`).join('\n')}

HIGH PRIORITY ISSUES
--------------------
${highDiscrepancies.map(d => `- ${d.type}: ${d.platformRecord?.transactionId || d.providerRecord?.transactionId} ($${Math.abs(d.difference || 0).toFixed(2)})`).join('\n')}

RECOMMENDATIONS
---------------
1. Investigate all critical issues immediately
2. Review high priority discrepancies within 24 hours
3. Schedule manual review of medium priority items
4. Update reconciliation procedures if needed
  `;
}

/**
 * Export reconciliation to CSV
 */
export function exportReconciliationToCSV(result: ReconciliationResult): string {
  const headers = [
    'Discrepancy ID',
    'Type',
    'Platform Transaction',
    'Provider Transaction',
    'Platform Amount',
    'Provider Amount',
    'Difference',
    'Severity',
    'Status',
  ];

  const rows = result.discrepancies.map(d => [
    d.id,
    d.type,
    d.platformRecord?.transactionId || 'N/A',
    d.providerRecord?.transactionId || 'N/A',
    d.platformRecord?.amount || 'N/A',
    d.providerRecord?.amount || 'N/A',
    d.difference?.toFixed(2) || 'N/A',
    d.severity,
    d.resolved ? 'Resolved' : 'Pending',
  ]);

  const csv = [
    headers.join(','),
    ...rows.map(row => row.map(cell => `"${cell}"`).join(',')),
  ].join('\n');

  return csv;
}

/**
 * Resolve discrepancy
 */
export function resolveDiscrepancy(
  discrepancy: DiscrepancyRecord,
  resolution: string
): DiscrepancyRecord {
  return {
    ...discrepancy,
    resolved: true,
    resolution,
  };
}

/**
 * Calculate reconciliation metrics
 */
export interface ReconciliationMetrics {
  averageMatchRate: number;
  totalDiscrepancies: number;
  criticalCount: number;
  highCount: number;
  mediumCount: number;
  lowCount: number;
  totalAmountDiscrepancy: number;
  providers: Record<string, ProviderMetrics>;
}

export interface ProviderMetrics {
  provider: string;
  matchRate: number;
  discrepancyCount: number;
  totalAmount: number;
  lastReconciliation: Date;
}

export function calculateMetrics(results: ReconciliationResult[]): ReconciliationMetrics {
  const matchRates = results.map(r => (r.totalMatched / r.totalRecords) * 100);
  const averageMatchRate = matchRates.reduce((a, b) => a + b, 0) / matchRates.length;

  const providers: Record<string, ProviderMetrics> = {};

  results.forEach(result => {
    if (!providers[result.provider]) {
      providers[result.provider] = {
        provider: result.provider,
        matchRate: 0,
        discrepancyCount: 0,
        totalAmount: 0,
        lastReconciliation: result.date,
      };
    }

    providers[result.provider].matchRate = (result.totalMatched / result.totalRecords) * 100;
    providers[result.provider].discrepancyCount += result.totalDiscrepancies;
    providers[result.provider].totalAmount += result.totalAmount;
    providers[result.provider].lastReconciliation = result.date;
  });

  return {
    averageMatchRate,
    totalDiscrepancies: results.reduce((sum, r) => sum + r.totalDiscrepancies, 0),
    criticalCount: results.reduce((sum, r) => sum + r.discrepancies.filter(d => d.severity === 'critical').length, 0),
    highCount: results.reduce((sum, r) => sum + r.discrepancies.filter(d => d.severity === 'high').length, 0),
    mediumCount: results.reduce((sum, r) => sum + r.discrepancies.filter(d => d.severity === 'medium').length, 0),
    lowCount: results.reduce((sum, r) => sum + r.discrepancies.filter(d => d.severity === 'low').length, 0),
    totalAmountDiscrepancy: results.reduce((sum, r) => sum + r.discrepancies.filter(d => d.difference).reduce((s, d) => s + Math.abs(d.difference || 0), 0), 0),
    providers,
  };
}

/**
 * Schedule daily reconciliation
 */
export interface ReconciliationSchedule {
  id: string;
  provider: string;
  frequency: 'daily' | 'weekly' | 'monthly';
  time: string; // HH:mm format
  enabled: boolean;
  lastRun?: Date;
  nextRun?: Date;
}

export function createReconciliationSchedule(
  provider: string,
  frequency: 'daily' | 'weekly' | 'monthly' = 'daily',
  time: string = '02:00'
): ReconciliationSchedule {
  return {
    id: `SCHED-${Date.now()}`,
    provider,
    frequency,
    time,
    enabled: true,
  };
}

/**
 * Get next reconciliation run time
 */
export function getNextReconciliationTime(schedule: ReconciliationSchedule): Date {
  const now = new Date();
  const [hours, minutes] = schedule.time.split(':').map(Number);

  let next = new Date(now);
  next.setHours(hours, minutes, 0, 0);

  if (next <= now) {
    if (schedule.frequency === 'daily') {
      next.setDate(next.getDate() + 1);
    } else if (schedule.frequency === 'weekly') {
      next.setDate(next.getDate() + 7);
    } else if (schedule.frequency === 'monthly') {
      next.setMonth(next.getMonth() + 1);
    }
  }

  return next;
}
