// Sovereign AI Risk Engine (SARE) - Core Service

import {
  RiskDataInputs,
  RiskOutputs,
  SystemAction,
  RiskSubsystem,
  LSAOutput,
  FXCPOutput,
  CNHEOutput,
  CSMOutput,
} from './types';
import { v4 as uuidv4 } from 'uuid';
import { logger } from '@/infrastructure/monitoring/logger';

export class SAREService {
  /**
   * Analyze all risk subsystems and generate outputs
   */
  async analyzeRisks(inputs: RiskDataInputs): Promise<RiskOutputs> {
    logger.info('SARE: Starting comprehensive risk analysis');

    const [sss, fxsp, clti, cda] = await Promise.all([
      this.calculateSovereignStressScores(inputs),
      this.calculateFXShockProbabilities(inputs),
      this.calculateCBDCLiquidityTension(inputs),
      this.calculateCommodityDepletion(inputs),
    ]);

    return {
      sovereignStressScore: sss,
      fxShockProbability: fxsp,
      cbdcLiquidityTension: clti,
      commodityDepletionAlert: cda,
    };
  }

  /**
   * Liquidity Shock Analyzer (LSA)
   */
  async analyzeLiquidityShocks(inputs: RiskDataInputs): Promise<LSAOutput[]> {
    const outputs: LSAOutput[] = [];

    if (!inputs.sovereignLiquidityReports) {
      return outputs;
    }

    for (const report of inputs.sovereignLiquidityReports) {
      const liquidityRatio =
        report.availableLiquidity / Math.max(report.requiredLiquidity, 1);

      // Calculate shock probability based on liquidity ratio
      let shockProbability = 0;
      if (liquidityRatio < 0.5) {
        shockProbability = 0.9 - liquidityRatio * 0.8; // High probability if ratio < 0.5
      } else if (liquidityRatio < 1.0) {
        shockProbability = (1.0 - liquidityRatio) * 0.5; // Moderate probability
      }

      const estimatedShockMagnitude = Math.max(0, (1.0 - liquidityRatio) * 100);

      let recommendedAction = 'MONITOR';
      if (liquidityRatio < 0.3) {
        recommendedAction = 'IMMEDIATE_LIQUIDITY_INJECTION';
      } else if (liquidityRatio < 0.5) {
        recommendedAction = 'LIQUIDITY_TOPUP';
      } else if (liquidityRatio < 0.8) {
        recommendedAction = 'ENHANCED_MONITORING';
      }

      outputs.push({
        sovereignBankId: report.sovereignBankId,
        liquidityShockProbability: Math.min(1.0, Math.max(0, shockProbability)),
        estimatedShockMagnitude,
        recommendedAction,
        timestamp: new Date(),
      });
    }

    return outputs;
  }

  /**
   * FX Collapse Predictor (FXCP)
   */
  async analyzeFXCollapse(inputs: RiskDataInputs): Promise<FXCPOutput[]> {
    const outputs: FXCPOutput[] = [];

    if (!inputs.fxVolatility) {
      return outputs;
    }

    // Group by currency pair
    const pairMap = new Map<string, number[]>();
    for (const vol of inputs.fxVolatility) {
      if (!pairMap.has(vol.currencyPair)) {
        pairMap.set(vol.currencyPair, []);
      }
      pairMap.get(vol.currencyPair)!.push(vol.volatility);
    }

    for (const [pair, volatilities] of pairMap.entries()) {
      const avgVolatility = volatilities.reduce((a, b) => a + b, 0) / volatilities.length;
      const maxVolatility = Math.max(...volatilities);
      const volatilitySpread = maxVolatility - avgVolatility;

      // Calculate collapse probability (10%+ movement)
      // Higher volatility and spread increase probability
      const collapseProbability = Math.min(
        1.0,
        (avgVolatility / 0.1) * 0.5 + (volatilitySpread / 0.05) * 0.5
      );

      const expectedVolatility = avgVolatility * 1.5; // Conservative estimate
      const confidence = volatilities.length > 10 ? 0.9 : 0.7; // More data = higher confidence

      outputs.push({
        currencyPair: pair,
        collapseProbability: Math.min(1.0, Math.max(0, collapseProbability)),
        expectedVolatility,
        confidence,
        timestamp: new Date(),
      });
    }

    return outputs;
  }

  /**
   * CBDC Network Health Engine (CNHE)
   */
  async analyzeCBDCHealth(inputs: RiskDataInputs): Promise<CNHEOutput[]> {
    const outputs: CNHEOutput[] = [];

    if (!inputs.cbdcMetrics) {
      return outputs;
    }

    // Group by sovereign
    const sovereignMap = new Map<string, typeof inputs.cbdcMetrics>();
    for (const metric of inputs.cbdcMetrics) {
      if (!sovereignMap.has(metric.sovereignBankId)) {
        sovereignMap.set(metric.sovereignBankId, []);
      }
      sovereignMap.get(metric.sovereignBankId)!.push(metric);
    }

    for (const [sovereignId, metrics] of sovereignMap.entries()) {
      const latest = metrics[metrics.length - 1];
      const avgVelocity =
        metrics.reduce((sum, m) => sum + m.velocity, 0) / metrics.length;

      // Calculate health score (0-100)
      let healthScore = 100;

      // Penalize low velocity
      if (avgVelocity < 1.0) {
        healthScore -= 20;
      } else if (avgVelocity < 2.0) {
        healthScore -= 10;
      }

      // Penalize low transaction volume
      if (latest.transactionVolume < 1000) {
        healthScore -= 15;
      }

      // Penalize low wallet count
      if (latest.walletCount < 100) {
        healthScore -= 10;
      }

      const issues: string[] = [];
      const recommendations: string[] = [];

      if (avgVelocity < 1.0) {
        issues.push('Low transaction velocity detected');
        recommendations.push('Investigate network congestion or user adoption barriers');
      }

      if (latest.transactionVolume < 1000) {
        issues.push('Low transaction volume');
        recommendations.push('Review CBDC adoption incentives');
      }

      if (latest.walletCount < 100) {
        issues.push('Low wallet count');
        recommendations.push('Enhance wallet onboarding process');
      }

      outputs.push({
        sovereignBankId: sovereignId,
        networkHealthScore: Math.max(0, Math.min(100, healthScore)),
        issues,
        recommendations,
        timestamp: new Date(),
      });
    }

    return outputs;
  }

  /**
   * Commodity Stress Model (CSM)
   */
  async analyzeCommodityStress(inputs: RiskDataInputs): Promise<CSMOutput[]> {
    const outputs: CSMOutput[] = [];

    if (!inputs.commodityReserves) {
      return outputs;
    }

    // Group by commodity type
    const commodityMap = new Map<string, typeof inputs.commodityReserves>();
    for (const reserve of inputs.commodityReserves) {
      if (!commodityMap.has(reserve.commodityType)) {
        commodityMap.set(reserve.commodityType, []);
      }
      commodityMap.get(reserve.commodityType)!.push(reserve);
    }

    for (const [commodityType, reserves] of commodityMap.entries()) {
      if (reserves.length < 2) {
        continue; // Need at least 2 data points to calculate depletion
      }

      // Sort by timestamp
      reserves.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());

      // Calculate depletion rate
      const first = reserves[0];
      const last = reserves[reserves.length - 1];
      const timeDiff = (last.timestamp.getTime() - first.timestamp.getTime()) / (1000 * 60 * 60 * 24); // days
      const reserveDiff = first.reserveAmount - last.reserveAmount;
      const depletionRate = timeDiff > 0 ? reserveDiff / timeDiff : 0;

      // Calculate stress level (0-100)
      let stressLevel = 0;
      if (last.backingRatio < 0.5) {
        stressLevel = 100 - last.backingRatio * 100;
      } else if (last.backingRatio < 0.8) {
        stressLevel = (0.8 - last.backingRatio) * 50;
      }

      // Estimate days until critical (assuming critical = 0.3 backing ratio)
      const criticalThreshold = last.reserveAmount * 0.3;
      const currentReserve = last.reserveAmount;
      const estimatedDaysUntilCritical =
        depletionRate > 0 ? (currentReserve - criticalThreshold) / depletionRate : Infinity;

      outputs.push({
        commodityType,
        stressLevel: Math.max(0, Math.min(100, stressLevel)),
        depletionRate,
        criticalThreshold,
        timestamp: new Date(),
      });
    }

    return outputs;
  }

  /**
   * Calculate Sovereign Stress Scores (SSS)
   */
  private async calculateSovereignStressScores(
    inputs: RiskDataInputs
  ): Promise<RiskOutputs['sovereignStressScore']> {
    const lsaOutputs = await this.analyzeLiquidityShocks(inputs);
    const cnheOutputs = await this.analyzeCBDCHealth(inputs);

    const scores: RiskOutputs['sovereignStressScore'] = [];

    // Combine LSA and CNHE data
    const sovereignSet = new Set<string>();
    lsaOutputs.forEach((o) => sovereignSet.add(o.sovereignBankId));
    cnheOutputs.forEach((o) => sovereignSet.add(o.sovereignBankId));

    for (const sovereignId of sovereignSet) {
      const lsa = lsaOutputs.find((o) => o.sovereignBankId === sovereignId);
      const cnhe = cnheOutputs.find((o) => o.sovereignBankId === sovereignId);

      // Calculate composite stress score
      let score = 50; // Base score

      if (lsa) {
        score += lsa.liquidityShockProbability * 30; // Liquidity contributes up to 30 points
      }

      if (cnhe) {
        score += (100 - cnhe.networkHealthScore) * 0.2; // Health contributes up to 20 points
      }

      // Normalize to 0-100
      score = Math.max(0, Math.min(100, score));

      scores.push({
        sovereignBankId: sovereignId,
        score,
        timestamp: new Date(),
        factors: {
          liquidityRatio: lsa ? 1 - lsa.liquidityShockProbability : 0.5,
          fxStability: 0.7, // Placeholder, would come from FXCP
          cbdcHealth: cnhe ? cnhe.networkHealthScore / 100 : 0.7,
          commodityBacking: 0.8, // Placeholder, would come from CSM
        },
      });
    }

    return scores;
  }

  /**
   * Calculate FX Shock Probabilities (FXSP)
   */
  private async calculateFXShockProbabilities(
    inputs: RiskDataInputs
  ): Promise<RiskOutputs['fxShockProbability']> {
    const fxcpOutputs = await this.analyzeFXCollapse(inputs);

    return fxcpOutputs.map((output) => ({
      currencyPair: output.currencyPair,
      probability: output.collapseProbability,
      timestamp: output.timestamp,
      confidence: output.confidence,
    }));
  }

  /**
   * Calculate CBDC Liquidity Tension Index (CLTI)
   */
  private async calculateCBDCLiquidityTension(
    inputs: RiskDataInputs
  ): Promise<RiskOutputs['cbdcLiquidityTension']> {
    const cnheOutputs = await this.analyzeCBDCHealth(inputs);
    const lsaOutputs = await this.analyzeLiquidityShocks(inputs);

    const tensions: RiskOutputs['cbdcLiquidityTension'] = [];

    for (const cnhe of cnheOutputs) {
      const lsa = lsaOutputs.find((o) => o.sovereignBankId === cnhe.sovereignBankId);

      // Calculate tension index (inverse of health, weighted by liquidity)
      const healthFactor = (100 - cnhe.networkHealthScore) / 100;
      const liquidityFactor = lsa ? lsa.liquidityShockProbability : 0.5;

      const index = (healthFactor * 0.6 + liquidityFactor * 0.4) * 100;

      let severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' = 'LOW';
      if (index >= 80) {
        severity = 'CRITICAL';
      } else if (index >= 60) {
        severity = 'HIGH';
      } else if (index >= 40) {
        severity = 'MEDIUM';
      }

      tensions.push({
        sovereignBankId: cnhe.sovereignBankId,
        index,
        timestamp: new Date(),
        severity,
      });
    }

    return tensions;
  }

  /**
   * Calculate Commodity Depletion Alerts (CDA)
   */
  private async calculateCommodityDepletion(
    inputs: RiskDataInputs
  ): Promise<RiskOutputs['commodityDepletionAlert']> {
    const csmOutputs = await this.analyzeCommodityStress(inputs);

    return csmOutputs.map((output) => {
      let alertLevel: 'WARNING' | 'CRITICAL' | 'EMERGENCY' = 'WARNING';
      if (output.stressLevel >= 80) {
        alertLevel = 'EMERGENCY';
      } else if (output.stressLevel >= 60) {
        alertLevel = 'CRITICAL';
      }

      return {
        commodityType: output.commodityType,
        depletionRate: output.depletionRate,
        estimatedDaysUntilCritical:
          output.depletionRate > 0
            ? Math.max(0, output.estimatedDaysUntilCritical || 0)
            : Infinity,
        timestamp: output.timestamp,
        alertLevel,
      };
    });
  }

  /**
   * Generate system actions based on risk outputs
   */
  async generateSystemActions(outputs: RiskOutputs): Promise<SystemAction[]> {
    const actions: SystemAction[] = [];

    // Generate liquidity top-up actions
    for (const sss of outputs.sovereignStressScore) {
      if (sss.score >= 70) {
        actions.push({
          id: `ACTION-${uuidv4()}`,
          type: 'LIQUIDITY_TOPUP',
          target: sss.sovereignBankId,
          parameters: {
            amount: 'AUTO', // Would be calculated by GLP
            priority: 'HIGH',
          },
          triggeredAt: new Date(),
          executed: false,
        });
      }
    }

    // Generate FX band tightening actions
    for (const fxsp of outputs.fxShockProbability) {
      if (fxsp.probability >= 0.7) {
        actions.push({
          id: `ACTION-${uuidv4()}`,
          type: 'FX_BAND_TIGHTENING',
          target: fxsp.currencyPair,
          parameters: {
            tighteningFactor: 0.5, // Reduce bands by 50%
          },
          triggeredAt: new Date(),
          executed: false,
        });
      }
    }

    // Generate CBDC throttling actions
    for (const clti of outputs.cbdcLiquidityTension) {
      if (clti.severity === 'CRITICAL' || clti.severity === 'HIGH') {
        actions.push({
          id: `ACTION-${uuidv4()}`,
          type: 'CBDC_THROTTLING',
          target: clti.sovereignBankId,
          parameters: {
            throttleRate: 0.5, // Reduce throughput by 50%
          },
          triggeredAt: new Date(),
          executed: false,
        });
      }
    }

    // Generate SCB risk escalations
    for (const sss of outputs.sovereignStressScore) {
      if (sss.score >= 80) {
        actions.push({
          id: `ACTION-${uuidv4()}`,
          type: 'SCB_RISK_ESCALATION',
          target: sss.sovereignBankId,
          parameters: {
            severity: 'CRITICAL',
            notify: true,
          },
          triggeredAt: new Date(),
          executed: false,
        });
      }
    }

    // Generate commodity intervention actions
    for (const cda of outputs.commodityDepletionAlert) {
      if (cda.alertLevel === 'EMERGENCY' || cda.alertLevel === 'CRITICAL') {
        actions.push({
          id: `ACTION-${uuidv4()}`,
          type: 'COMMODITY_INTERVENTION',
          target: cda.commodityType,
          parameters: {
            interventionType: 'RESERVE_INJECTION',
            urgency: cda.alertLevel,
          },
          triggeredAt: new Date(),
          executed: false,
        });
      }
    }

    logger.info(`SARE: Generated ${actions.length} system actions`);

    return actions;
  }
}

export const sareService = new SAREService();

