// Bond Risk & Oversight Service
// SARE and ARI integration

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { logger } from '@/infrastructure/monitoring/logger';
import { sriCalculatorService } from '@/core/risk/sri/sri-calculator.service';


export type AssessmentType = 'sare' | 'ari' | 'composite';
export type RiskTier = 'low' | 'medium' | 'high' | 'critical';

export interface BondRiskAssessmentRequest {
  bondId?: string;
  syntheticBondId?: string;
  assessmentType: AssessmentType;
}

export interface BondRiskAssessmentResult {
  assessmentId: string;
  compositeRiskScore: Decimal;
  riskTier: RiskTier;
  sareScore?: Decimal;
  ariCompliance: boolean;
}

export class BondRiskService {
  /**
   * Assess bond risk
   */
  async assessBondRisk(request: BondRiskAssessmentRequest): Promise<BondRiskAssessmentResult> {
    logger.info('GRU: Assessing bond risk', { request });

    const assessmentId = `ASSESS-${uuidv4()}`;

    // Get bond
    let bond;
    if (request.bondId) {
      bond = await prisma.gruBond.findUnique({
        where: { bondId: request.bondId },
      });
      if (!bond) {
        throw new Error(`Bond not found: ${request.bondId}`);
      }
    } else if (request.syntheticBondId) {
      bond = await prisma.syntheticGruBond.findUnique({
        where: { syntheticBondId: request.syntheticBondId },
      });
      if (!bond) {
        throw new Error(`Synthetic bond not found: ${request.syntheticBondId}`);
      }
    } else {
      throw new Error('Either bondId or syntheticBondId must be provided');
    }

    // Calculate SARE metrics
    const sareMetrics = await this.calculateSAREMetrics(bond);

    // Calculate ARI compliance
    const ariCompliance = await this.checkARICompliance(bond);

    // Calculate composite risk score
    const compositeRiskScore = await this.calculateCompositeRiskScore(sareMetrics, ariCompliance);

    // Determine risk tier
    const riskTier = this.determineRiskTier(compositeRiskScore);

    // Save assessment
    await prisma.bondRiskAssessment.create({
      data: {
        assessmentId,
        bondId: request.bondId,
        syntheticBondId: request.syntheticBondId,
        assessmentType: request.assessmentType,
        sovereignDefaultExposure: sareMetrics.sovereignDefaultExposure,
        fxLinkedRisk: sareMetrics.fxLinkedRisk,
        metalIndexDependency: sareMetrics.metalIndexDependency,
        creditRisk: sareMetrics.creditRisk,
        marketRisk: sareMetrics.marketRisk,
        liquidityRisk: sareMetrics.liquidityRisk,
        operationalRisk: sareMetrics.operationalRisk,
        compositeRiskScore,
        riskTier,
        sareScore: sareMetrics.sareScore,
        ariCompliance,
        assessmentDetails: JSON.stringify({
          sareMetrics,
          ariCompliance,
        }),
        assessedAt: new Date(),
      },
    });

    // Create compliance record if needed
    if (!ariCompliance) {
      await prisma.bondComplianceRecord.create({
        data: {
          recordId: `COMP-${uuidv4()}`,
          assessmentId,
          complianceType: 'regulatory',
          complianceStatus: 'violation',
          violationType: 'ari_non_compliance',
          ariAction: 'automated_alert',
        },
      });
    }

    logger.info('GRU: Bond risk assessed', { assessmentId, riskTier, compositeRiskScore: compositeRiskScore.toString() });

    return {
      assessmentId,
      compositeRiskScore,
      riskTier,
      sareScore: sareMetrics.sareScore,
      ariCompliance,
    };
  }

  /**
   * Calculate SARE metrics
   */
  private async calculateSAREMetrics(bond: any): Promise<{
    sovereignDefaultExposure: Decimal;
    fxLinkedRisk: Decimal;
    metalIndexDependency: Decimal;
    creditRisk: Decimal;
    marketRisk: Decimal;
    liquidityRisk: Decimal;
    operationalRisk: Decimal;
    sareScore: Decimal;
  }> {
    // Get SRI for sovereign bank
    let sareScore = new Decimal(50); // Default
    if (bond.sovereignBankId) {
      try {
        const sriResult = await sriCalculatorService.calculateSRI(bond.sovereignBankId);
        sareScore = new Decimal(sriResult.sriScore);
      } catch (error) {
        logger.warn('GRU: Failed to get SRI for SARE calculation', { error });
      }
    }

    // Sovereign default exposure (based on SRI)
    const sovereignDefaultExposure = sareScore.div(100).times(bond.principalAmount || new Decimal(0));

    // FX-linked risk (simplified)
    const fxLinkedRisk = new Decimal(0.02); // 2% default

    // Metal-index dependency (simplified)
    const metalIndexDependency = new Decimal(0.01); // 1% default

    // Credit risk (based on SRI)
    const creditRisk = sareScore.div(100);

    // Market risk (simplified)
    const marketRisk = new Decimal(0.03); // 3% default

    // Liquidity risk (simplified)
    const liquidityRisk = new Decimal(0.02); // 2% default

    // Operational risk (simplified)
    const operationalRisk = new Decimal(0.01); // 1% default

    return {
      sovereignDefaultExposure,
      fxLinkedRisk,
      metalIndexDependency,
      creditRisk,
      marketRisk,
      liquidityRisk,
      operationalRisk,
      sareScore,
    };
  }

  /**
   * Check ARI compliance
   */
  private async checkARICompliance(bond: any): Promise<boolean> {
    // Simplified ARI compliance check
    // In production, would use actual ARI service

    // Check if bond is active
    if (bond.status !== 'active') {
      return false;
    }

    // Check if bond has valid principal amount
    if (!bond.principalAmount || bond.principalAmount.lte(0)) {
      return false;
    }

    // Check synthetic market integrity (simplified)
    // In production, would check for manipulation patterns, etc.

    return true;
  }

  /**
   * Calculate composite risk score
   */
  private async calculateCompositeRiskScore(
    sareMetrics: any,
    ariCompliance: boolean
  ): Promise<Decimal> {
    // Weighted composite risk score
    const weights = {
      credit: 0.3,
      market: 0.2,
      liquidity: 0.2,
      operational: 0.1,
      fx: 0.1,
      metal: 0.1,
    };

    let compositeScore = new Decimal(0);
    compositeScore = compositeScore.plus(sareMetrics.creditRisk.times(weights.credit * 100));
    compositeScore = compositeScore.plus(sareMetrics.marketRisk.times(weights.market * 100));
    compositeScore = compositeScore.plus(sareMetrics.liquidityRisk.times(weights.liquidity * 100));
    compositeScore = compositeScore.plus(sareMetrics.operationalRisk.times(weights.operational * 100));
    compositeScore = compositeScore.plus(sareMetrics.fxLinkedRisk.times(weights.fx * 100));
    compositeScore = compositeScore.plus(sareMetrics.metalIndexDependency.times(weights.metal * 100));

    // ARI compliance penalty
    if (!ariCompliance) {
      compositeScore = compositeScore.plus(10); // Add 10 points for non-compliance
    }

    // Normalize to 0-100
    return compositeScore.gt(100) ? new Decimal(100) : compositeScore;
  }

  /**
   * Determine risk tier
   */
  private determineRiskTier(riskScore: Decimal): RiskTier {
    const score = riskScore.toNumber();
    if (score <= 25) {
      return 'low';
    } else if (score <= 50) {
      return 'medium';
    } else if (score <= 75) {
      return 'high';
    } else {
      return 'critical';
    }
  }

  /**
   * Get risk assessment
   */
  async getRiskAssessment(assessmentId: string) {
    return await prisma.bondRiskAssessment.findUnique({
      where: { assessmentId },
      include: {
        complianceRecords: true,
      },
    });
  }

  /**
   * Get latest risk assessment for bond
   */
  async getLatestRiskAssessment(bondId?: string, syntheticBondId?: string) {
    return await prisma.bondRiskAssessment.findFirst({
      where: {
        bondId: bondId || undefined,
        syntheticBondId: syntheticBondId || undefined,
      },
      orderBy: { assessedAt: 'desc' },
      include: {
        complianceRecords: true,
      },
    });
  }

  /**
   * Monitor bond risk (continuous monitoring)
   */
  async monitorBondRisk(bondId?: string, syntheticBondId?: string): Promise<BondRiskAssessmentResult> {
    return await this.assessBondRisk({
      bondId,
      syntheticBondId,
      assessmentType: 'composite',
    });
  }
}

export const bondRiskService = new BondRiskService();

