// SIRE Metrics Service
// FX volatility tracking
// Liquidity buffer level monitoring
// SRI risk score integration
// Synthetic settlement cost calculation
// Commodity index integration

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';


export interface SireMetrics {
  fxCost?: Decimal;
  fxVolatility?: Decimal;
  liquidityPenalty?: Decimal;
  liquidityBufferLevel?: Decimal;
  sriScore?: Decimal;
  ssuAdjustment?: Decimal;
  syntheticSettlementCost?: Decimal;
  commodityIndex?: Record<string, unknown>;
}

export class SireMetricsService {
  /**
   * Calculate routing metrics
   */
  async calculateMetrics(
    routeId: string,
    sourceBankId: string,
    destinationBankId: string
  ): Promise<SireMetrics> {
    // Get FX cost
    const fxCost = await this.calculateFxCost(sourceBankId, destinationBankId);

    // Get FX volatility
    const fxVolatility = await this.getFxVolatility(sourceBankId, destinationBankId);

    // Get liquidity penalty
    const liquidityPenalty = await this.calculateLiquidityPenalty(sourceBankId);

    // Get liquidity buffer level
    const liquidityBufferLevel = await this.getLiquidityBufferLevel(sourceBankId);

    // Get SRI score
    const sriScore = await this.getSriScore(sourceBankId);

    // Calculate SSU adjustment
    const ssuAdjustment = await this.calculateSsuAdjustment(sourceBankId, destinationBankId);

    // Calculate synthetic settlement cost
    const syntheticSettlementCost = await this.calculateSyntheticSettlementCost(sourceBankId, destinationBankId);

    // Get commodity index
    const commodityIndex = await this.getCommodityIndex();

    return {
      fxCost,
      fxVolatility,
      liquidityPenalty,
      liquidityBufferLevel,
      sriScore,
      ssuAdjustment,
      syntheticSettlementCost,
      commodityIndex,
    };
  }

  /**
   * Calculate FX cost
   */
  private async calculateFxCost(
    sourceBankId: string,
    destinationBankId: string
  ): Promise<Decimal> {
    // Get FX rate
    const fxPair = await prisma.fxPair.findFirst({
      where: {
        status: 'active',
      },
    });

    if (!fxPair) {
      return new Decimal(0);
    }

    // Get latest trade
    const latestTrade = await prisma.fxTrade.findFirst({
      where: {
        fxPairId: fxPair.id,
        status: 'executed',
      },
      orderBy: { executedAt: 'desc' },
    });

    if (!latestTrade) {
      return new Decimal(0);
    }

    // Calculate FX cost (in production, would be more sophisticated)
    return new Decimal(latestTrade.price).mul(0.001); // 0.1% spread
  }

  /**
   * Get FX volatility
   */
  private async getFxVolatility(
    sourceBankId: string,
    destinationBankId: string
  ): Promise<Decimal> {
    // In production, would calculate historical volatility
    // For now, return default
    return new Decimal(0.05); // 5% volatility
  }

  /**
   * Calculate liquidity penalty
   */
  private async calculateLiquidityPenalty(sovereignBankId: string): Promise<Decimal> {
    // Get liquidity score
    const liquidityScore = await prisma.liquidityScore.findFirst({
      where: {
        sovereignBankId,
      },
      orderBy: { calculatedAt: 'desc' },
    });

    if (!liquidityScore) {
      return new Decimal(0);
    }

    // Higher score = lower penalty
    // Score < 85 = penalty
    if (liquidityScore.score.lt(85)) {
      return new Decimal(85).minus(liquidityScore.score).mul(0.1);
    }

    return new Decimal(0);
  }

  /**
   * Get liquidity buffer level
   */
  private async getLiquidityBufferLevel(sovereignBankId: string): Promise<Decimal> {
    const liquidityPools = await prisma.liquidityPool.findMany({
      where: {
        sovereignBankId,
      },
    });

    if (liquidityPools.length === 0) {
      return new Decimal(0);
    }

    const totalAvailable = liquidityPools.reduce(
      (sum, pool) => sum.plus(pool.availableLiquidity),
      new Decimal(0)
    );

    const totalLiquidity = liquidityPools.reduce(
      (sum, pool) => sum.plus(pool.totalLiquidity),
      new Decimal(0)
    );

    if (totalLiquidity.eq(0)) {
      return new Decimal(0);
    }

    return totalAvailable.div(totalLiquidity);
  }

  /**
   * Get SRI score
   */
  private async getSriScore(sovereignBankId: string): Promise<Decimal | null> {
    const sri = await prisma.sovereignRiskIndex.findFirst({
      where: {
        sovereignBankId,
        status: 'active',
      },
      orderBy: { calculatedAt: 'desc' },
    });

    if (!sri) {
      return null;
    }

    // Convert to risk cost (lower score = higher risk cost)
    return new Decimal(100).minus(sri.sriScore);
  }

  /**
   * Calculate SSU adjustment
   */
  private async calculateSsuAdjustment(
    sourceBankId: string,
    destinationBankId: string
  ): Promise<Decimal> {
    // In production, would check if SSU route is optimal
    // For now, return small adjustment
    return new Decimal(0.001); // 0.1% adjustment
  }

  /**
   * Calculate synthetic settlement cost
   */
  private async calculateSyntheticSettlementCost(
    sourceBankId: string,
    destinationBankId: string
  ): Promise<Decimal> {
    // In production, would calculate cost of using SSU
    // For now, return default
    return new Decimal(0.002); // 0.2% cost
  }

  /**
   * Get commodity index
   */
  private async getCommodityIndex(): Promise<Record<string, unknown>> {
    const commodities = await prisma.commodity.findMany({
      where: {},
    });

    const index: Record<string, unknown> = {};

    for (const commodity of commodities) {
      index[commodity.commodityType] = {
        price: commodity.spotPrice.toString(),
        unit: commodity.unit,
        lastUpdated: commodity.lastUpdated,
      };
    }

    return index;
  }

  /**
   * Save metrics
   */
  async saveMetrics(decisionId: string, metrics: SireMetrics): Promise<string> {
    const metricsId = `SIRE-MET-${uuidv4()}`;

    await prisma.sireRoutingMetrics.create({
      data: {
        metricsId,
        decisionId,
        fxVolatility: metrics.fxVolatility || null,
        liquidityBufferLevel: metrics.liquidityBufferLevel || null,
        sriScore: metrics.sriScore || null,
        syntheticSettlementCost: metrics.syntheticSettlementCost || null,
        commodityIndex: metrics.commodityIndex || null,
        calculatedAt: new Date(),
      },
    });

    return metricsId;
  }

  /**
   * Get metrics for bank
   */
  async getMetricsForBank(sovereignBankId: string, limit: number = 100) {
    // Get decisions for bank
    const decisions = await prisma.sireRoutingDecision.findMany({
      where: {
        OR: [
          { sourceBankId: sovereignBankId },
          { destinationBankId: sovereignBankId },
        ],
      },
      orderBy: { decisionTimestamp: 'desc' },
      take: limit,
      include: {
        metrics: true,
      },
    });

    return decisions.map((d) => d.metrics).filter((m) => m !== null);
  }
}

export const sireMetricsService = new SireMetricsService();

