// GRU SARE Integration Service
// Volume II: Supranational Reserve Framework
// Integrates with SARE (Sovereign AI Risk Engine) for reserve adequacy evaluation

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


export interface ReserveAdequacyResult {
  sovereignBankId?: string;
  entityId?: string;
  reserveAdequacy: Decimal; // 0-100 scale
  totalReserves: Decimal;
  requiredReserves: Decimal;
  adequacyRatio: Decimal;
  sriScore?: Decimal;
  riskFactors: string[];
  recommendations: string[];
}

export interface SovereignExposureResult {
  sovereignBankId: string;
  totalExposure: Decimal;
  exposureByPool: Record<string, Decimal>;
  riskLevel: 'low' | 'medium' | 'high' | 'critical';
}

export class GruSareIntegrationService {
  private sriCalculator: SRICalculatorService;

  constructor() {
    this.sriCalculator = new SRICalculatorService();
  }

  /**
   * Evaluate sovereign exposure in reserve pools
   */
  async evaluateSovereignExposure(
    sovereignBankId: string
  ): Promise<SovereignExposureResult> {
    logger.info('GRU SARE: Evaluating sovereign exposure', {
      sovereignBankId,
    });

    // Get all allocations for this sovereign bank
    const allocations = await prisma.gru_reserve_allocations.findMany({
      where: {
        sovereignBankId,
        status: 'confirmed',
      },
      include: {
        pool: true,
      },
    });

    const totalExposure = allocations.reduce(
      (sum, alloc) => sum.plus(alloc.amount),
      new Decimal(0)
    );

    const exposureByPool: Record<string, Decimal> = {};
    for (const alloc of allocations) {
      const poolId = alloc.poolId;
      if (!exposureByPool[poolId]) {
        exposureByPool[poolId] = new Decimal(0);
      }
      exposureByPool[poolId] = exposureByPool[poolId].plus(alloc.amount);
    }

    // Determine risk level based on exposure
    let riskLevel: 'low' | 'medium' | 'high' | 'critical' = 'low';

    // Get SRI score for context
    const sriScores = await prisma.sovereign_risk_indices.findMany({
      where: {
        sovereignBankId,
        status: 'active',
      },
      orderBy: { calculatedAt: 'desc' },
      take: 1,
    });

    const sriScore = sriScores.length > 0 ? sriScores[0].sriScore : null;

    if (sriScore) {
      if (sriScore.lt(40)) {
        riskLevel = 'critical';
      } else if (sriScore.lt(60)) {
        riskLevel = 'high';
      } else if (sriScore.lt(80)) {
        riskLevel = 'medium';
      }
    }

    // Adjust risk level based on exposure concentration
    const poolCount = Object.keys(exposureByPool).length;
    if (poolCount === 1 && totalExposure.gt(100000000)) {
      // High concentration in single pool
      if (riskLevel === 'low') riskLevel = 'medium';
      else if (riskLevel === 'medium') riskLevel = 'high';
    }

    logger.info('GRU SARE: Sovereign exposure evaluated', {
      sovereignBankId,
      totalExposure: totalExposure.toString(),
      riskLevel,
    });

    return {
      sovereignBankId,
      totalExposure,
      exposureByPool,
      riskLevel,
    };
  }

  /**
   * Calculate reserve adequacy
   * Evaluates if reserves are adequate for the entity's needs
   */
  async calculateReserveAdequacy(
    entityId?: string,
    sovereignBankId?: string
  ): Promise<ReserveAdequacyResult> {
    logger.info('GRU SARE: Calculating reserve adequacy', {
      entityId,
      sovereignBankId,
    });

    let totalReserves = new Decimal(0);
    let sriScore: Decimal | undefined;

    if (entityId) {
      // Get reserves for supranational entity
      const pools = await prisma.gru_reserve_pools.findMany({
        where: { entityId },
      });

      totalReserves = pools.reduce(
        (sum, pool) => sum.plus(pool.totalReserves),
        new Decimal(0)
      );
    } else if (sovereignBankId) {
      // Get reserves for sovereign bank
      const allocations = await prisma.gru_reserve_allocations.findMany({
        where: {
          sovereignBankId,
          status: 'confirmed',
        },
      });

      totalReserves = allocations.reduce(
        (sum, alloc) => sum.plus(alloc.amount),
        new Decimal(0)
      );

      // Get SRI score
      const sriScores = await prisma.sovereign_risk_indices.findMany({
        where: {
          sovereignBankId,
          status: 'active',
        },
        orderBy: { calculatedAt: 'desc' },
        take: 1,
      });

      sriScore = sriScores.length > 0 ? sriScores[0].sriScore : undefined;
    } else {
      throw new Error('Either entityId or sovereignBankId must be provided');
    }

    // Calculate required reserves
    // In production, would use more sophisticated calculation
    // For now, use a simple multiplier based on SRI score
    let requiredReserves = totalReserves; // Default: 1:1 ratio

    if (sriScore) {
      // Higher SRI (lower risk) = lower reserve requirement
      // Lower SRI (higher risk) = higher reserve requirement
      const riskMultiplier = new Decimal(100).minus(sriScore).dividedBy(50); // 0-2 range
      requiredReserves = totalReserves.times(riskMultiplier);
    } else {
      // Default: require reserves equal to current reserves (1:1)
      requiredReserves = totalReserves;
    }

    // Calculate adequacy ratio
    const adequacyRatio =
      requiredReserves.gt(0)
        ? totalReserves.dividedBy(requiredReserves)
        : new Decimal(1);

    // Calculate adequacy score (0-100)
    let reserveAdequacy = adequacyRatio.times(100);
    if (reserveAdequacy.gt(100)) reserveAdequacy = new Decimal(100);
    if (reserveAdequacy.lt(0)) reserveAdequacy = new Decimal(0);

    // Identify risk factors
    const riskFactors: string[] = [];
    const recommendations: string[] = [];

    if (adequacyRatio.lt(0.8)) {
      riskFactors.push('Reserve adequacy below 80% threshold');
      recommendations.push('Increase reserve allocations');
    }

    if (sriScore && sriScore.lt(60)) {
      riskFactors.push('SRI score below 60 (elevated risk)');
      recommendations.push('Improve sovereign risk metrics');
    }

    if (totalReserves.lt(1000000)) {
      riskFactors.push('Total reserves below minimum threshold');
      recommendations.push('Build reserve buffer');
    }

    if (riskFactors.length === 0) {
      recommendations.push('Reserve adequacy is satisfactory');
    }

    logger.info('GRU SARE: Reserve adequacy calculated', {
      entityId,
      sovereignBankId,
      reserveAdequacy: reserveAdequacy.toString(),
      adequacyRatio: adequacyRatio.toString(),
    });

    return {
      sovereignBankId,
      entityId,
      reserveAdequacy,
      totalReserves,
      requiredReserves,
      adequacyRatio,
      sriScore,
      riskFactors,
      recommendations,
    };
  }

  /**
   * Monitor reserve pools for adequacy
   */
  async monitorReservePools(): Promise<
    Array<{ poolId: string; adequacy: Decimal; status: string }>
  > {
    logger.info('GRU SARE: Monitoring reserve pools');

    const pools = await prisma.gru_reserve_pools.findMany({
      where: { status: 'active' },
    });

    const results = [];

    for (const pool of pools) {
      const adequacy = await this.calculateReserveAdequacy(
        pool.entityId || undefined
      );

      let status = 'adequate';
      if (adequacy.reserveAdequacy.lt(80)) {
        status = 'inadequate';
      } else if (adequacy.reserveAdequacy.lt(90)) {
        status = 'marginal';
      }

      results.push({
        poolId: pool.poolId,
        adequacy: adequacy.reserveAdequacy,
        status,
      });
    }

    logger.info('GRU SARE: Reserve pool monitoring completed', {
      poolsMonitored: results.length,
    });

    return results;
  }

  /**
   * Get reserve adequacy report
   */
  async getReserveAdequacyReport(
    entityId?: string,
    sovereignBankId?: string
  ) {
    const adequacy = await this.calculateReserveAdequacy(
      entityId,
      sovereignBankId
    );

    let exposure: SovereignExposureResult | null = null;
    if (sovereignBankId) {
      exposure = await this.evaluateSovereignExposure(sovereignBankId);
    }

    return {
      adequacy,
      exposure,
      timestamp: new Date(),
    };
  }
}

export const gruSareIntegrationService = new GruSareIntegrationService();

