/**
 * Compliance checks for credential issuance
 * KYC verification, AML screening, sanctions checking, identity verification
 */

import fetch from 'node-fetch';
import { getEnv } from './env';

export interface ComplianceCheckResult {
  passed: boolean;
  checks: Array<{
    name: string;
    passed: boolean;
    reason?: string;
    details?: unknown;
  }>;
  riskScore: number; // 0-100, higher is riskier
}

export interface ComplianceCheckConfig {
  enableKYC?: boolean;
  enableAML?: boolean;
  enableSanctions?: boolean;
  enableIdentityVerification?: boolean;
  kycProvider?: string;
  amlProvider?: string;
  sanctionsProvider?: string;
  riskThreshold?: number; // Block issuance if risk score exceeds this
}

/**
 * Compliance checking service
 */
export class ComplianceService {
  private config: ComplianceCheckConfig;

  constructor(config?: ComplianceCheckConfig) {
    const env = getEnv();
    this.config = config || {
      enableKYC: true,
      enableAML: true,
      enableSanctions: true,
      enableIdentityVerification: true,
      kycProvider: env.KYC_PROVIDER_URL,
      amlProvider: env.AML_PROVIDER_URL,
      sanctionsProvider: env.SANCTIONS_PROVIDER_URL,
      riskThreshold: 70,
    };
  }

  /**
   * Perform all compliance checks
   */
  async performComplianceChecks(
    subjectDid: string,
    subjectData: {
      name?: string;
      email?: string;
      phone?: string;
      address?: string;
      dateOfBirth?: string;
      nationality?: string;
    }
  ): Promise<ComplianceCheckResult> {
    const checks: ComplianceCheckResult['checks'] = [];
    let riskScore = 0;

    // KYC Verification
    if (this.config.enableKYC) {
      const kycResult = await this.performKYCCheck(subjectDid, subjectData);
      checks.push(kycResult);
      if (!kycResult.passed) {
        riskScore += 30;
      }
    }

    // AML Screening
    if (this.config.enableAML) {
      const amlResult = await this.performAMLCheck(subjectDid, subjectData);
      checks.push(amlResult);
      if (!amlResult.passed) {
        riskScore += 40;
      }
    }

    // Sanctions Checking
    if (this.config.enableSanctions) {
      const sanctionsResult = await this.performSanctionsCheck(subjectDid, subjectData);
      checks.push(sanctionsResult);
      if (!sanctionsResult.passed) {
        riskScore += 50; // High risk for sanctions matches
      }
    }

    // Identity Verification
    if (this.config.enableIdentityVerification) {
      const identityResult = await this.performIdentityVerification(subjectDid, subjectData);
      checks.push(identityResult);
      if (!identityResult.passed) {
        riskScore += 20;
      }
    }

    const passed = checks.every((c) => c.passed) && riskScore < (this.config.riskThreshold || 70);

    return {
      passed,
      checks,
      riskScore: Math.min(riskScore, 100),
    };
  }

  /**
   * Perform KYC (Know Your Customer) check
   */
  private async performKYCCheck(
    subjectDid: string,
    subjectData: Record<string, unknown>
  ): Promise<{ name: string; passed: boolean; reason?: string; details?: unknown }> {
    try {
      if (this.config.kycProvider) {
        const response = await fetch(`${this.config.kycProvider}/verify`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ did: subjectDid, ...subjectData }),
        });

        if (!response.ok) {
          return {
            name: 'KYC Check',
            passed: false,
            reason: `KYC provider returned ${response.status}`,
          };
        }

        const result = (await response.json()) as { verified: boolean; details?: unknown };
        return {
          name: 'KYC Check',
          passed: result.verified,
          reason: result.verified ? undefined : 'KYC verification failed',
          details: result.details,
        };
      }

      // Fallback: basic validation
      const hasRequiredFields = Boolean(subjectData.name && (subjectData.email || subjectData.phone));
      return {
        name: 'KYC Check',
        passed: hasRequiredFields,
        reason: hasRequiredFields ? undefined : 'Missing required KYC fields',
      };
    } catch (error) {
      return {
        name: 'KYC Check',
        passed: false,
        reason: error instanceof Error ? error.message : 'KYC check failed',
      };
    }
  }

  /**
   * Perform AML (Anti-Money Laundering) screening
   */
  private async performAMLCheck(
    subjectDid: string,
    subjectData: Record<string, unknown>
  ): Promise<{ name: string; passed: boolean; reason?: string; details?: unknown }> {
    try {
      if (this.config.amlProvider) {
        const response = await fetch(`${this.config.amlProvider}/screen`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ did: subjectDid, ...subjectData }),
        });

        if (!response.ok) {
          return {
            name: 'AML Screening',
            passed: false,
            reason: `AML provider returned ${response.status}`,
          };
        }

        const result = (await response.json()) as { cleared: boolean; riskLevel?: string; details?: unknown };
        return {
          name: 'AML Screening',
          passed: result.cleared,
          reason: result.cleared ? undefined : `AML risk level: ${result.riskLevel || 'high'}`,
          details: result.details,
        };
      }

      // Fallback: always pass if no provider configured
      return {
        name: 'AML Screening',
        passed: true,
        reason: 'AML provider not configured',
      };
    } catch (error) {
      return {
        name: 'AML Screening',
        passed: false,
        reason: error instanceof Error ? error.message : 'AML check failed',
      };
    }
  }

  /**
   * Perform sanctions check
   */
  private async performSanctionsCheck(
    subjectDid: string,
    subjectData: Record<string, unknown>
  ): Promise<{ name: string; passed: boolean; reason?: string; details?: unknown }> {
    try {
      if (this.config.sanctionsProvider) {
        const response = await fetch(`${this.config.sanctionsProvider}/check`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ did: subjectDid, ...subjectData }),
        });

        if (!response.ok) {
          return {
            name: 'Sanctions Check',
            passed: false,
            reason: `Sanctions provider returned ${response.status}`,
          };
        }

        const result = (await response.json()) as { match: boolean; matches?: unknown[]; details?: unknown };
        return {
          name: 'Sanctions Check',
          passed: !result.match,
          reason: result.match ? 'Subject matches sanctions list' : undefined,
          details: result.details,
        };
      }

      // Fallback: always pass if no provider configured
      return {
        name: 'Sanctions Check',
        passed: true,
        reason: 'Sanctions provider not configured',
      };
    } catch (error) {
      return {
        name: 'Sanctions Check',
        passed: false,
        reason: error instanceof Error ? error.message : 'Sanctions check failed',
      };
    }
  }

  /**
   * Perform identity verification
   */
  private async performIdentityVerification(
    _subjectDid: string,
    subjectData: Record<string, unknown>
  ): Promise<{ name: string; passed: boolean; reason?: string; details?: unknown }> {
    try {
      // Basic identity verification: check if DID is valid and has associated identity
      // In production, this would verify against identity providers, government databases, etc.
      const hasIdentityData = subjectData.name || subjectData.email || subjectData.phone;

      return {
        name: 'Identity Verification',
        passed: !!hasIdentityData,
        reason: hasIdentityData ? undefined : 'Insufficient identity data',
      };
    } catch (error) {
      return {
        name: 'Identity Verification',
        passed: false,
        reason: error instanceof Error ? error.message : 'Identity verification failed',
      };
    }
  }
}

/**
 * Get default compliance service
 */
let defaultComplianceService: ComplianceService | null = null;

export function getComplianceService(): ComplianceService {
  if (!defaultComplianceService) {
    defaultComplianceService = new ComplianceService();
  }
  return defaultComplianceService;
}

