/**
 * Risk Assessment Engine
 * Evaluates applications and determines auto-approve, auto-reject, or manual review
 */

export interface RiskAssessmentInput {
  applicationId: string;
  kycResults: {
    documentVerification?: {
      passed: boolean;
      documentType: string;
      riskFlags: string[];
    };
    livenessCheck?: {
      passed: boolean;
      livenessScore: number;
      faceMatch: boolean;
    };
    riskScore?: number;
  };
  sanctionsResults: {
    sanctionsMatch: boolean;
    pepMatch: boolean;
    riskScore: number;
    matches: Array<{
      type: 'sanctions' | 'pep' | 'adverse_media';
      matchScore: number;
    }>;
  };
  applicantData: {
    nationality?: string;
    address?: {
      country?: string;
    };
  };
}

export interface RiskAssessmentResult {
  applicationId: string;
  assessedAt: string;
  overallRiskScore: number;
  riskBands: {
    kyc: 'low' | 'medium' | 'high';
    sanctions: 'low' | 'medium' | 'high';
    geographic: 'low' | 'medium' | 'high';
  };
  decision: 'auto_approve' | 'auto_reject' | 'manual_review';
  reasons: string[];
  requiresEDD: boolean;
  flags: string[];
}

/**
 * Risk Assessment Engine
 */
export class RiskAssessmentEngine {
  private highRiskCountries: string[] = [
    // TODO: Configure high-risk countries based on sanctions lists and policy
    'IR', 'KP', 'SY', // Example: Iran, North Korea, Syria
  ];

  /**
   * Assess application risk
   */
  async assessRisk(input: RiskAssessmentInput): Promise<RiskAssessmentResult> {
    const riskBands = {
      kyc: this.assessKYCRisk(input.kycResults),
      sanctions: this.assessSanctionsRisk(input.sanctionsResults),
      geographic: this.assessGeographicRisk(input.applicantData),
    };

    const overallRiskScore = this.calculateOverallRiskScore(
      input.kycResults.riskScore || 0.5,
      input.sanctionsResults.riskScore,
      riskBands
    );

    const reasons: string[] = [];
    const flags: string[] = [];

    // Collect reasons and flags
    if (input.kycResults.documentVerification && !input.kycResults.documentVerification.passed) {
      reasons.push('Document verification failed');
      flags.push('document_verification_failed');
    }

    if (input.kycResults.livenessCheck && !input.kycResults.livenessCheck.passed) {
      reasons.push('Liveness check failed');
      flags.push('liveness_check_failed');
    }

    if (input.sanctionsResults.sanctionsMatch) {
      reasons.push('Sanctions list match');
      flags.push('sanctions_match');
    }

    if (input.sanctionsResults.pepMatch) {
      reasons.push('PEP match');
      flags.push('pep_match');
    }

    if (riskBands.geographic === 'high') {
      reasons.push('High-risk geography');
      flags.push('high_risk_geography');
    }

    // Determine decision
    let decision: 'auto_approve' | 'auto_reject' | 'manual_review';
    const requiresEDD = overallRiskScore > 0.7 || input.sanctionsResults.pepMatch || riskBands.geographic === 'high';

    if (overallRiskScore < 0.3 && riskBands.kyc === 'low' && riskBands.sanctions === 'low' && riskBands.geographic === 'low') {
      decision = 'auto_approve';
      reasons.push('Low overall risk score');
    } else if (
      overallRiskScore > 0.8 ||
      input.sanctionsResults.sanctionsMatch ||
      (input.kycResults.documentVerification && !input.kycResults.documentVerification.passed) ||
      (input.kycResults.livenessCheck && !input.kycResults.livenessCheck.passed)
    ) {
      decision = 'auto_reject';
      reasons.push('High risk or failed checks');
    } else {
      decision = 'manual_review';
      reasons.push('Medium risk - requires manual review');
    }

    return {
      applicationId: input.applicationId,
      assessedAt: new Date().toISOString(),
      overallRiskScore,
      riskBands,
      decision,
      reasons,
      requiresEDD,
      flags,
    };
  }

  /**
   * Assess KYC risk
   */
  private assessKYCRisk(kycResults: RiskAssessmentInput['kycResults']): 'low' | 'medium' | 'high' {
    if (!kycResults.documentVerification?.passed || !kycResults.livenessCheck?.passed) {
      return 'high';
    }

    const riskScore = kycResults.riskScore || 0.5;

    if (riskScore < 0.3) {
      return 'low';
    } else if (riskScore > 0.7) {
      return 'high';
    } else {
      return 'medium';
    }
  }

  /**
   * Assess sanctions risk
   */
  private assessSanctionsRisk(sanctionsResults: RiskAssessmentInput['sanctionsResults']): 'low' | 'medium' | 'high' {
    if (sanctionsResults.sanctionsMatch) {
      return 'high';
    }

    if (sanctionsResults.pepMatch || sanctionsResults.riskScore > 0.7) {
      return 'high';
    } else if (sanctionsResults.riskScore > 0.4) {
      return 'medium';
    } else {
      return 'low';
    }
  }

  /**
   * Assess geographic risk
   */
  private assessGeographicRisk(applicantData: RiskAssessmentInput['applicantData']): 'low' | 'medium' | 'high' {
    const country = applicantData.nationality || applicantData.address?.country;

    if (!country) {
      return 'medium'; // Unknown geography
    }

    if (this.highRiskCountries.includes(country.toUpperCase())) {
      return 'high';
    }

    // TODO: Add medium-risk countries list
    // if (this.mediumRiskCountries.includes(country.toUpperCase())) {
    //   return 'medium';
    // }

    return 'low';
  }

  /**
   * Calculate overall risk score
   */
  private calculateOverallRiskScore(
    kycRiskScore: number,
    sanctionsRiskScore: number,
    riskBands: {
      kyc: 'low' | 'medium' | 'high';
      sanctions: 'low' | 'medium' | 'high';
      geographic: 'low' | 'medium' | 'high';
    }
  ): number {
    // Weighted risk score calculation
    const kycWeight = 0.4;
    const sanctionsWeight = 0.4;
    const geographicWeight = 0.2;

    const kycScore = riskBands.kyc === 'high' ? 0.9 : riskBands.kyc === 'medium' ? 0.5 : 0.1;
    const sanctionsScore = riskBands.sanctions === 'high' ? 0.9 : riskBands.sanctions === 'medium' ? 0.5 : 0.1;
    const geographicScore = riskBands.geographic === 'high' ? 0.9 : riskBands.geographic === 'medium' ? 0.5 : 0.1;

    const weightedScore =
      kycRiskScore * kycWeight + sanctionsRiskScore * sanctionsWeight + geographicScore * geographicWeight;

    // Combine with band scores
    const bandScore = (kycScore * kycWeight + sanctionsScore * sanctionsWeight + geographicScore * geographicWeight) * 0.5;

    return Math.min(1.0, (weightedScore + bandScore) / 1.5);
  }
}

/**
 * Get risk assessment engine instance
 */
let riskEngine: RiskAssessmentEngine | null = null;

export function getRiskAssessmentEngine(): RiskAssessmentEngine {
  if (!riskEngine) {
    riskEngine = new RiskAssessmentEngine();
  }
  return riskEngine;
}

