import type {
  ComplianceDecisionEngine,
  ComplianceEvaluationInput,
  ComplianceEvaluationResult,
} from './ComplianceDecisionEngine.js';
import { MockComplianceDecisionEngine } from './ComplianceDecisionEngine.js';
import fs from 'node:fs';
import path from 'node:path';

type Volume13Rule = {
  id: string;
  decision?: string;
  trigger?: { riskHints?: string[]; amountGte?: number };
};

type SanctionsEntry = {
  id: string;
  names?: string[];
  active?: boolean;
};

/**
 * Production compliance engine: Volume 13 rules + internal sanctions list.
 * Vendor adapter hook via COMPLIANCE_VENDOR env (worldcheck|chainalysis|internal).
 */
export class Volume13ComplianceDecisionEngine implements ComplianceDecisionEngine {
  private readonly mockFallback: MockComplianceDecisionEngine;
  private readonly rules: Volume13Rule[];
  private readonly sanctions: SanctionsEntry[];
  private readonly vendor: string;
  private auditCounter = 0;

  constructor(options?: { rulesPath?: string; sanctionsPath?: string }) {
    const root = process.env.PROXMOX_ROOT || path.resolve(process.cwd(), '../..');
    const rulesPath =
      options?.rulesPath ||
      path.join(root, 'config/hybx-omnl-dbis/volume13-aml-decision-rules.v1.json');
    const sanctionsPath =
      options?.sanctionsPath ||
      path.join(root, 'config/compliance/internal-sanctions-list.v1.json');

    this.mockFallback = new MockComplianceDecisionEngine();
    this.vendor = process.env.COMPLIANCE_VENDOR || 'internal';
    this.rules = fs.existsSync(rulesPath)
      ? JSON.parse(fs.readFileSync(rulesPath, 'utf8')).rules ?? []
      : [];
    this.sanctions = fs.existsSync(sanctionsPath)
      ? JSON.parse(fs.readFileSync(sanctionsPath, 'utf8')).entries ?? []
      : [];
  }

  private nextAuditId(): string {
    this.auditCounter += 1;
    return `audit-v13-${this.vendor}-${this.auditCounter}`;
  }

  private matchSanctions(entityId: string): boolean {
    const needle = entityId.toLowerCase();
    return this.sanctions.some(
      (e) =>
        e.active !== false &&
        (e.id.toLowerCase() === needle ||
          (e.names ?? []).some((n) => needle.includes(n.toLowerCase())))
    );
  }

  async evaluateTransaction(
    input: ComplianceEvaluationInput
  ): Promise<ComplianceEvaluationResult> {
    const hints = input.riskHints ?? [];

    if (this.matchSanctions(input.entityId) || hints.includes('sanctions_hit')) {
      return {
        decision: 'block',
        risk_score: 100,
        reason_codes: ['SANCTIONS_HIT', `VENDOR_${this.vendor.toUpperCase()}`],
        evidence_refs: ['volume13-sanctions-screen'],
        manual_review_required: true,
        audit_event_id: this.nextAuditId(),
      };
    }

    for (const rule of this.rules) {
      const trigger = rule.trigger ?? {};
      if (trigger.riskHints?.some((h) => hints.includes(h))) {
        return {
          decision: (rule.decision as ComplianceEvaluationResult['decision']) ?? 'review',
          risk_score: 80,
          reason_codes: [rule.id],
          evidence_refs: [`volume13-${rule.id}`],
          manual_review_required: true,
          audit_event_id: this.nextAuditId(),
        };
      }
      if (trigger.amountGte != null && Number(input.amount) >= trigger.amountGte) {
        return {
          decision: (rule.decision as ComplianceEvaluationResult['decision']) ?? 'hold',
          risk_score: 65,
          reason_codes: [rule.id, 'AMOUNT_THRESHOLD'],
          evidence_refs: [`volume13-${rule.id}`],
          manual_review_required: true,
          audit_event_id: this.nextAuditId(),
        };
      }
    }

    return this.mockFallback.evaluateTransaction(input);
  }

  async evaluateEntity(
    entityId: string,
    tenantId: string
  ): Promise<ComplianceEvaluationResult> {
    if (this.matchSanctions(entityId)) {
      return {
        decision: 'reject',
        risk_score: 95,
        reason_codes: ['ENTITY_SANCTIONS_MATCH'],
        evidence_refs: [`sanctions-${entityId}`],
        manual_review_required: true,
        audit_event_id: this.nextAuditId(),
      };
    }
    return this.mockFallback.evaluateEntity(entityId, tenantId);
  }

  async evaluateCounterparty(
    counterpartyId: string,
    tenantId: string
  ): Promise<ComplianceEvaluationResult> {
    return this.evaluateEntity(counterpartyId, tenantId);
  }
}

export function createComplianceDecisionEngine(): ComplianceDecisionEngine {
  if (process.env.OMNL_COMPLIANCE_GATE !== '1') {
    return new MockComplianceDecisionEngine();
  }
  return new Volume13ComplianceDecisionEngine();
}
