import type {
  ComplianceDecisionEngine,
  ComplianceEvaluationInput,
  ComplianceEvaluationResult,
} from '@dbis/integration-foundation';
import { MockComplianceDecisionEngine } from '@dbis/integration-foundation';
import fs from 'node:fs';
import path from 'node:path';

type Rule = { id: string; decision?: string; trigger?: { riskHints?: string[]; amountGte?: number } };
type SanctionEntry = { id: string; names?: string[]; active?: boolean };

function loadJson<T>(p: string, fallback: T): T {
  try {
    return JSON.parse(fs.readFileSync(p, 'utf8')) as T;
  } catch {
    return fallback;
  }
}

export class Volume13ComplianceDecisionEngine implements ComplianceDecisionEngine {
  private readonly fallback = new MockComplianceDecisionEngine();
  private readonly rules: Rule[];
  private readonly sanctions: SanctionEntry[];
  private readonly vendor: string;
  private auditCounter = 0;

  constructor(root: string) {
    this.vendor = process.env.COMPLIANCE_VENDOR || 'internal';
    const rulesDoc = loadJson<{ rules?: Rule[] }>(
      path.join(root, 'config/hybx-omnl-dbis/volume13-aml-decision-rules.v1.json'),
      {}
    );
    const sanctionsDoc = loadJson<{ entries?: SanctionEntry[] }>(
      path.join(root, 'config/compliance/internal-sanctions-list.v1.json'),
      {}
    );
    this.rules = rulesDoc.rules ?? [];
    this.sanctions = sanctionsDoc.entries ?? [];
  }

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

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

  async evaluateTransaction(input: ComplianceEvaluationInput): Promise<ComplianceEvaluationResult> {
    const hints = input.riskHints ?? [];
    if (this.sanctioned(input.entityId) || hints.includes('sanctions_hit')) {
      return {
        decision: 'block',
        risk_score: 100,
        reason_codes: ['SANCTIONS_HIT'],
        evidence_refs: ['volume13-sanctions'],
        manual_review_required: true,
        audit_event_id: this.auditId(),
      };
    }
    for (const rule of this.rules) {
      const t = rule.trigger ?? {};
      if (t.riskHints?.some((h) => hints.includes(h))) {
        return {
          decision: (rule.decision as ComplianceEvaluationResult['decision']) ?? 'review',
          risk_score: 80,
          reason_codes: [rule.id],
          evidence_refs: [rule.id],
          manual_review_required: true,
          audit_event_id: this.auditId(),
        };
      }
      if (t.amountGte != null && Number(input.amount) >= t.amountGte) {
        return {
          decision: (rule.decision as ComplianceEvaluationResult['decision']) ?? 'hold',
          risk_score: 65,
          reason_codes: [rule.id],
          evidence_refs: [rule.id],
          manual_review_required: true,
          audit_event_id: this.auditId(),
        };
      }
    }
    return this.fallback.evaluateTransaction(input);
  }

  async evaluateEntity(entityId: string, tenantId: string): Promise<ComplianceEvaluationResult> {
    if (this.sanctioned(entityId)) {
      return {
        decision: 'reject',
        risk_score: 95,
        reason_codes: ['ENTITY_SANCTIONS'],
        evidence_refs: [entityId],
        manual_review_required: true,
        audit_event_id: this.auditId(),
      };
    }
    return this.fallback.evaluateEntity(entityId, tenantId);
  }

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

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