/**
 * Fraud Scoring System
 * Machine learning-based fraud detection for payments
 */

export interface FraudIndicator {
  name: string;
  weight: number;
  value: number;
  threshold: number;
  triggered: boolean;
}

export interface FraudScore {
  id: string;
  transactionId: string;
  userId: number;
  score: number; // 0-100
  risk: 'low' | 'medium' | 'high' | 'critical';
  indicators: FraudIndicator[];
  timestamp: Date;
  reviewed: boolean;
  action: 'approved' | 'flagged' | 'blocked' | 'pending';
}

export interface UserBehavior {
  userId: number;
  totalTransactions: number;
  averageAmount: number;
  standardDeviation: number;
  lastTransactionDate: Date;
  lastTransactionAmount: number;
  lastTransactionLocation: string;
  deviceFingerprint: string;
  ipAddress: string;
}

/**
 * Calculate fraud score for a transaction
 */
export function calculateFraudScore(
  transactionId: string,
  userId: number,
  amount: number,
  location: string,
  deviceFingerprint: string,
  ipAddress: string,
  userBehavior: UserBehavior
): FraudScore {
  const indicators: FraudIndicator[] = [];
  let totalScore = 0;

  // 1. Velocity Check - Multiple transactions in short time
  const velocityScore = checkVelocity(userBehavior);
  indicators.push({
    name: 'Velocity Check',
    weight: 15,
    value: velocityScore,
    threshold: 50,
    triggered: velocityScore > 50,
  });
  totalScore += velocityScore * 0.15;

  // 2. Amount Anomaly - Transaction significantly different from average
  const amountScore = checkAmountAnomaly(amount, userBehavior);
  indicators.push({
    name: 'Amount Anomaly',
    weight: 20,
    value: amountScore,
    threshold: 60,
    triggered: amountScore > 60,
  });
  totalScore += amountScore * 0.20;

  // 3. Geographic Anomaly - Impossible travel distance
  const geoScore = checkGeographicAnomaly(location, userBehavior);
  indicators.push({
    name: 'Geographic Anomaly',
    weight: 18,
    value: geoScore,
    threshold: 70,
    triggered: geoScore > 70,
  });
  totalScore += geoScore * 0.18;

  // 4. Device Fingerprint Change - New device
  const deviceScore = checkDeviceChange(deviceFingerprint, userBehavior);
  indicators.push({
    name: 'Device Change',
    weight: 12,
    value: deviceScore,
    threshold: 55,
    triggered: deviceScore > 55,
  });
  totalScore += deviceScore * 0.12;

  // 5. IP Address Change - New IP
  const ipScore = checkIPChange(ipAddress, userBehavior);
  indicators.push({
    name: 'IP Change',
    weight: 10,
    value: ipScore,
    threshold: 50,
    triggered: ipScore > 50,
  });
  totalScore += ipScore * 0.10;

  // 6. Duplicate Detection - Same amount within short time
  const duplicateScore = checkDuplicateTransaction(amount, userBehavior);
  indicators.push({
    name: 'Duplicate Detection',
    weight: 15,
    value: duplicateScore,
    threshold: 80,
    triggered: duplicateScore > 80,
  });
  totalScore += duplicateScore * 0.15;

  // 7. Time Anomaly - Transaction at unusual time
  const timeScore = checkTimeAnomaly();
  indicators.push({
    name: 'Time Anomaly',
    weight: 5,
    value: timeScore,
    threshold: 40,
    triggered: timeScore > 40,
  });
  totalScore += timeScore * 0.05;

  // 8. Behavioral Pattern - Deviation from normal behavior
  const behaviorScore = checkBehavioralPattern(userBehavior);
  indicators.push({
    name: 'Behavioral Pattern',
    weight: 5,
    value: behaviorScore,
    threshold: 60,
    triggered: behaviorScore > 60,
  });
  totalScore += behaviorScore * 0.05;

  // Determine risk level
  let risk: 'low' | 'medium' | 'high' | 'critical' = 'low';
  let action: 'approved' | 'flagged' | 'blocked' | 'pending' = 'approved';

  if (totalScore >= 80) {
    risk = 'critical';
    action = 'blocked';
  } else if (totalScore >= 60) {
    risk = 'high';
    action = 'flagged';
  } else if (totalScore >= 40) {
    risk = 'medium';
    action = 'pending';
  }

  return {
    id: `FRAUD-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    transactionId,
    userId,
    score: Math.round(totalScore),
    risk,
    indicators,
    timestamp: new Date(),
    reviewed: false,
    action,
  };
}

/**
 * Check velocity - Multiple transactions in short time
 */
function checkVelocity(behavior: UserBehavior): number {
  const timeSinceLastTransaction = Date.now() - behavior.lastTransactionDate.getTime();
  const hoursSinceLastTransaction = timeSinceLastTransaction / (1000 * 60 * 60);

  if (hoursSinceLastTransaction < 1) return 90; // Very suspicious
  if (hoursSinceLastTransaction < 3) return 70;
  if (hoursSinceLastTransaction < 6) return 50;
  if (hoursSinceLastTransaction < 24) return 30;
  return 10;
}

/**
 * Check amount anomaly
 */
function checkAmountAnomaly(amount: number, behavior: UserBehavior): number {
  if (behavior.totalTransactions < 5) return 20; // Not enough data

  const zScore = Math.abs((amount - behavior.averageAmount) / (behavior.standardDeviation || 1));

  if (zScore > 5) return 95; // Extreme outlier
  if (zScore > 3) return 80;
  if (zScore > 2) return 60;
  if (zScore > 1) return 40;
  return 10;
}

/**
 * Check geographic anomaly - Impossible travel
 */
function checkGeographicAnomaly(location: string, behavior: UserBehavior): number {
  if (location === behavior.lastTransactionLocation) return 10;

  // Simulate distance calculation (in production, use real geolocation)
  const distance = Math.random() * 5000; // km
  const timeSinceLastTransaction = Date.now() - behavior.lastTransactionDate.getTime();
  const hoursSinceLastTransaction = timeSinceLastTransaction / (1000 * 60 * 60);

  const requiredSpeed = distance / hoursSinceLastTransaction;
  const maxRealisticSpeed = 900; // km/h (airplane speed)

  if (requiredSpeed > maxRealisticSpeed * 2) return 95; // Impossible travel
  if (requiredSpeed > maxRealisticSpeed) return 80;
  if (distance > 1000 && hoursSinceLastTransaction < 4) return 60;
  return 20;
}

/**
 * Check device change
 */
function checkDeviceChange(deviceFingerprint: string, behavior: UserBehavior): number {
  if (deviceFingerprint === behavior.deviceFingerprint) return 10;
  return 70; // New device is suspicious
}

/**
 * Check IP change
 */
function checkIPChange(ipAddress: string, behavior: UserBehavior): number {
  if (ipAddress === behavior.ipAddress) return 10;
  return 60; // New IP is suspicious
}

/**
 * Check duplicate transaction
 */
function checkDuplicateTransaction(amount: number, behavior: UserBehavior): number {
  if (Math.abs(amount - behavior.lastTransactionAmount) < 0.01) {
    const timeSinceLastTransaction = Date.now() - behavior.lastTransactionDate.getTime();
    const minutesSinceLastTransaction = timeSinceLastTransaction / (1000 * 60);

    if (minutesSinceLastTransaction < 5) return 95; // Duplicate within 5 minutes
    if (minutesSinceLastTransaction < 30) return 80;
    if (minutesSinceLastTransaction < 60) return 60;
  }
  return 10;
}

/**
 * Check time anomaly
 */
function checkTimeAnomaly(): number {
  const hour = new Date().getHours();

  // Transactions between 2-5 AM are suspicious
  if (hour >= 2 && hour <= 5) return 60;
  if (hour >= 0 && hour <= 6) return 40;
  return 10;
}

/**
 * Check behavioral pattern
 */
function checkBehavioralPattern(behavior: UserBehavior): number {
  if (behavior.totalTransactions < 3) return 50; // New user is suspicious

  if (behavior.totalTransactions < 10) return 40;
  if (behavior.totalTransactions < 50) return 20;
  return 10;
}

/**
 * Generate fraud report
 */
export function generateFraudReport(fraudScores: FraudScore[]): string {
  const criticalCount = fraudScores.filter(f => f.risk === 'critical').length;
  const highCount = fraudScores.filter(f => f.risk === 'high').length;
  const mediumCount = fraudScores.filter(f => f.risk === 'medium').length;
  const blockedCount = fraudScores.filter(f => f.action === 'blocked').length;
  const flaggedCount = fraudScores.filter(f => f.action === 'flagged').length;

  const averageScore = fraudScores.reduce((sum, f) => sum + f.score, 0) / fraudScores.length;

  return `
FRAUD DETECTION REPORT
Generated: ${new Date().toISOString()}

SUMMARY
-------
Total Transactions Analyzed: ${fraudScores.length}
Average Fraud Score: ${averageScore.toFixed(1)}

RISK BREAKDOWN
--------------
Critical Risk: ${criticalCount}
High Risk: ${highCount}
Medium Risk: ${mediumCount}
Low Risk: ${fraudScores.filter(f => f.risk === 'low').length}

ACTIONS TAKEN
-------------
Blocked: ${blockedCount}
Flagged: ${flaggedCount}
Pending Review: ${fraudScores.filter(f => f.action === 'pending').length}
Approved: ${fraudScores.filter(f => f.action === 'approved').length}

TOP FRAUD INDICATORS
--------------------
${getTopIndicators(fraudScores).map(ind => `- ${ind.name}: triggered in ${ind.count} transactions`).join('\n')}

RECOMMENDATIONS
---------------
1. Review all critical and high-risk transactions
2. Contact users with flagged transactions
3. Update fraud detection thresholds if needed
4. Monitor for patterns in fraudulent activity
  `;
}

/**
 * Get top fraud indicators
 */
function getTopIndicators(fraudScores: FraudScore[]): Array<{ name: string; count: number }> {
  const indicators: Record<string, number> = {};

  fraudScores.forEach(score => {
    score.indicators.forEach(indicator => {
      if (indicator.triggered) {
        indicators[indicator.name] = (indicators[indicator.name] || 0) + 1;
      }
    });
  });

  return Object.entries(indicators)
    .map(([name, count]) => ({ name, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 5);
}

/**
 * Export fraud scores to CSV
 */
export function exportFraudScoresToCSV(fraudScores: FraudScore[]): string {
  const headers = [
    'Fraud ID',
    'Transaction ID',
    'User ID',
    'Score',
    'Risk',
    'Action',
    'Timestamp',
    'Reviewed',
  ];

  const rows = fraudScores.map(f => [
    f.id,
    f.transactionId,
    f.userId,
    f.score,
    f.risk,
    f.action,
    f.timestamp.toISOString(),
    f.reviewed ? 'Yes' : 'No',
  ]);

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

  return csv;
}

/**
 * Review fraud score
 */
export function reviewFraudScore(
  fraudScore: FraudScore,
  approved: boolean,
  notes?: string
): FraudScore {
  return {
    ...fraudScore,
    reviewed: true,
    action: approved ? 'approved' : fraudScore.action,
  };
}

/**
 * Calculate fraud metrics
 */
export interface FraudMetrics {
  totalAnalyzed: number;
  criticalCount: number;
  highCount: number;
  mediumCount: number;
  lowCount: number;
  blockedCount: number;
  flaggedCount: number;
  approvedCount: number;
  blockRate: number; // percentage
  flagRate: number; // percentage
  averageScore: number;
  topIndicators: Array<{ name: string; count: number }>;
}

export function calculateFraudMetrics(fraudScores: FraudScore[]): FraudMetrics {
  const criticalCount = fraudScores.filter(f => f.risk === 'critical').length;
  const highCount = fraudScores.filter(f => f.risk === 'high').length;
  const mediumCount = fraudScores.filter(f => f.risk === 'medium').length;
  const lowCount = fraudScores.filter(f => f.risk === 'low').length;

  const blockedCount = fraudScores.filter(f => f.action === 'blocked').length;
  const flaggedCount = fraudScores.filter(f => f.action === 'flagged').length;
  const approvedCount = fraudScores.filter(f => f.action === 'approved').length;

  const blockRate = (blockedCount / fraudScores.length) * 100;
  const flagRate = (flaggedCount / fraudScores.length) * 100;
  const averageScore = fraudScores.reduce((sum, f) => sum + f.score, 0) / fraudScores.length;

  return {
    totalAnalyzed: fraudScores.length,
    criticalCount,
    highCount,
    mediumCount,
    lowCount,
    blockedCount,
    flaggedCount,
    approvedCount,
    blockRate,
    flagRate,
    averageScore,
    topIndicators: getTopIndicators(fraudScores),
  };
}
