// M-RTGS Risk Monitor
// Real-time risk controls: velocity, liquidity, FX slip, commodity shocks, CBDC routing

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';


export interface RiskAlert {
  alertId: string;
  alertType: string;
  severity: 'low' | 'medium' | 'high' | 'critical';
  description: string;
  metrics: Record<string, unknown>;
}

export class MrtgsRiskMonitorService {
  /**
   * Monitor transaction velocity
   */
  async monitorVelocity(
    entityId: string,
    entityType: string,
    timeWindow: number = 3600000 // 1 hour
  ): Promise<RiskAlert | null> {
    const windowStart = new Date(Date.now() - timeWindow);

    // Count transactions in time window
    const transactionCount = await prisma.mrtgs_settlements.count({
      where: {
        OR: [
          { sourceBankId: entityId },
          { destinationBankId: entityId },
        ],
        settledAt: {
          gte: windowStart,
        },
        status: 'settled',
      },
    });

    // Velocity threshold (transactions per hour)
    const threshold = entityType === 'sovereign_bank' ? 1000 : 100;

    if (transactionCount > threshold) {
      const alertId = `MRTGS-ALERT-${uuidv4()}`;
      
      // Get most recent settlement for this entity
      const recentSettlement = await prisma.mrtgs_settlements.findFirst({
        where: {
          OR: [
            { sourceBankId: entityId },
            { destinationBankId: entityId },
          ],
        },
        orderBy: { settledAt: 'desc' },
      });

      const alert = await prisma.mrtgs_risk_alerts.create({
        data: {
          alertId,
          settlementId: recentSettlement?.settlementId || '',
          alertType: 'velocity',
          severity: transactionCount > threshold * 2 ? 'critical' : 'high',
          description: `High transaction velocity detected: ${transactionCount} transactions in ${timeWindow / 1000 / 60} minutes`,
          metrics: {
            transactionCount,
            threshold,
            timeWindow,
            entityId,
            entityType,
          },
          status: 'active',
        },
      });

      logger.warn('M-RTGS: Velocity alert', { alertId, transactionCount, threshold });

      return {
        alertId: alert.alertId,
        alertType: alert.alertType,
        severity: alert.severity as 'low' | 'medium' | 'high' | 'critical',
        description: alert.description,
        metrics: alert.behavioral_metrics as Record<string, unknown>,
      };
    }

    return null;
  }

  /**
   * Monitor liquidity congestion
   */
  async monitorLiquidityCongestion(
    currencyCode: string,
    assetType: string
  ): Promise<RiskAlert | null> {
    // Get pending queue size
    const pendingCount = await prisma.mrtgs_queues.count({
      where: {
        currencyCode,
        assetType,
        status: 'queued',
      },
    });

    // Get total liquidity for asset
    const totalLiquidity = await this.getTotalLiquidity(currencyCode, assetType);

    // Congestion threshold: > 50 pending transactions or > 80% of liquidity reserved
    const congestionThreshold = 50;
    const liquidityThreshold = totalLiquidity.times(0.8);

    const reservedLiquidity = await this.getReservedLiquidity(currencyCode, assetType);

    if (pendingCount > congestionThreshold || reservedLiquidity.gt(liquidityThreshold)) {
      const alertId = `MRTGS-ALERT-${uuidv4()}`;
      const alert = await prisma.mrtgs_risk_alerts.create({
        data: {
          alertId,
          settlementId: '',
          alertType: 'liquidity_congestion',
          severity: reservedLiquidity.gt(liquidityThreshold) ? 'critical' : 'high',
          description: `Liquidity congestion detected: ${pendingCount} pending transactions, ${reservedLiquidity.toString()} reserved`,
          metrics: {
            pendingCount,
            totalLiquidity: totalLiquidity.toString(),
            reservedLiquidity: reservedLiquidity.toString(),
            currencyCode,
            assetType,
          },
          status: 'active',
        },
      });

      logger.warn('M-RTGS: Liquidity congestion alert', {
        alertId,
        pendingCount,
        reservedLiquidity: reservedLiquidity.toString(),
      });

      return {
        alertId: alert.alertId,
        alertType: alert.alertType,
        severity: alert.severity as 'low' | 'medium' | 'high' | 'critical',
        description: alert.description,
        metrics: alert.behavioral_metrics as Record<string, unknown>,
      };
    }

    return null;
  }

  /**
   * Monitor FX slip
   */
  async monitorFxSlip(
    currencyPair: string,
    expectedRate: Decimal,
    actualRate: Decimal
  ): Promise<RiskAlert | null> {
    const slipPercentage = actualRate.minus(expectedRate).div(expectedRate).abs().times(100);

    // Alert if slip > 1%
    if (slipPercentage.gt(1)) {
      const alertId = `MRTGS-ALERT-${uuidv4()}`;
      const severity = slipPercentage.gt(5) ? 'critical' : slipPercentage.gt(2) ? 'high' : 'medium';

      const alert = await prisma.mrtgs_risk_alerts.create({
        data: {
          alertId,
          settlementId: '',
          alertType: 'fx_slip',
          severity,
          description: `FX slip detected: ${slipPercentage.toString()}% deviation`,
          metrics: {
            currencyPair,
            expectedRate: expectedRate.toString(),
            actualRate: actualRate.toString(),
            slipPercentage: slipPercentage.toString(),
          },
          status: 'active',
        },
      });

      logger.warn('M-RTGS: FX slip alert', {
        alertId,
        slipPercentage: slipPercentage.toString(),
      });

      return {
        alertId: alert.alertId,
        alertType: alert.alertType,
        severity: alert.severity as 'low' | 'medium' | 'high' | 'critical',
        description: alert.description,
        metrics: alert.behavioral_metrics as Record<string, unknown>,
      };
    }

    return null;
  }

  /**
   * Monitor commodity price shocks
   */
  async monitorCommodityShock(
    commodityType: string,
    previousPrice: Decimal,
    currentPrice: Decimal
  ): Promise<RiskAlert | null> {
    const priceChange = currentPrice.minus(previousPrice).div(previousPrice).abs().times(100);

    // Alert if price change > 5%
    if (priceChange.gt(5)) {
      const alertId = `MRTGS-ALERT-${uuidv4()}`;
      const severity = priceChange.gt(10) ? 'critical' : 'high';

      const alert = await prisma.mrtgs_risk_alerts.create({
        data: {
          alertId,
          settlementId: '',
          alertType: 'commodity_shock',
          severity,
          description: `Commodity price shock detected: ${priceChange.toString()}% change`,
          metrics: {
            commodityType,
            previousPrice: previousPrice.toString(),
            currentPrice: currentPrice.toString(),
            priceChange: priceChange.toString(),
          },
          status: 'active',
        },
      });

      logger.warn('M-RTGS: Commodity shock alert', {
        alertId,
        priceChange: priceChange.toString(),
      });

      return {
        alertId: alert.alertId,
        alertType: alert.alertType,
        severity: alert.severity as 'low' | 'medium' | 'high' | 'critical',
        description: alert.description,
        metrics: alert.behavioral_metrics as Record<string, unknown>,
      };
    }

    return null;
  }

  /**
   * Monitor CBDC routing anomalies
   */
  async monitorCbdcRouting(
    sourceBankId: string,
    destinationBankId: string,
    routingPattern: Record<string, unknown>
  ): Promise<RiskAlert | null> {
    // Check for unusual routing patterns
    // Simplified: alert if routing through > 3 intermediate nodes
    const intermediateNodes = (routingPattern.path as string[] || []).length - 2;

    if (intermediateNodes > 3) {
      const alertId = `MRTGS-ALERT-${uuidv4()}`;
      const alert = await prisma.mrtgs_risk_alerts.create({
        data: {
          alertId,
          settlementId: '',
          alertType: 'cbdc_routing_anomaly',
          severity: 'medium',
          description: `Unusual CBDC routing pattern: ${intermediateNodes} intermediate nodes`,
          metrics: {
            sourceBankId,
            destinationBankId,
            intermediateNodes,
            routingPattern,
          },
          status: 'active',
        },
      });

      logger.warn('M-RTGS: CBDC routing anomaly', {
        alertId,
        intermediateNodes,
      });

      return {
        alertId: alert.alertId,
        alertType: alert.alertType,
        severity: alert.severity as 'low' | 'medium' | 'high' | 'critical',
        description: alert.description,
        metrics: alert.behavioral_metrics as Record<string, unknown>,
      };
    }

    return null;
  }

  /**
   * Get total liquidity for asset
   */
  private async getTotalLiquidity(currencyCode: string, assetType: string): Promise<Decimal> {
    const accounts = await prisma.bank_accounts.findMany({
      where: {
        currencyCode,
        assetType,
        status: 'active',
      },
    });

    return accounts.reduce(
      (sum, account) => sum.plus(account.balance),
      new Decimal(0)
    );
  }

  /**
   * Get reserved liquidity
   */
  private async getReservedLiquidity(currencyCode: string, assetType: string): Promise<Decimal> {
    const accounts = await prisma.bank_accounts.findMany({
      where: {
        currencyCode,
        assetType,
        status: 'active',
      },
    });

    return accounts.reduce(
      (sum, account) => sum.plus(account.reservedBalance),
      new Decimal(0)
    );
  }
}

export const mrtgsRiskMonitorService = new MrtgsRiskMonitorService();

