// SSU Composition Service
// Real-time basket rebalancing
// Underlying asset valuation
// LAM (Liquidity Adjustment Mechanism) calculations
// Composition verification

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


export interface SsuCompositionWeights {
  currencyWeight: Decimal; // 40%
  commodityWeight: Decimal; // 30%
  cbdcWeight: Decimal; // 20%
  lamWeight: Decimal; // 10%
}

export interface UnderlyingAssets {
  topSovereigns: string[]; // Top 10 SCBs
  commodities: string[]; // Gold, oil, rare metals
  cbdcs: string[]; // Sovereign CBDC tier
}

export class SsuCompositionService {
  /**
   * Initialize SSU composition with default weights
   * 40% currency, 30% commodity, 20% CBDC, 10% LAM
   */
  async initializeComposition(ssuId: string): Promise<string> {
    const composition = await prisma.ssuComposition.create({
      data: {
        ssuId,
        currencyWeight: new Decimal(0.40), // 40%
        commodityWeight: new Decimal(0.30), // 30%
        cbdcWeight: new Decimal(0.20), // 20%
        lamWeight: new Decimal(0.10), // 10%
        topSovereigns: this.getTopSovereigns(),
        commodities: ['GOLD', 'OIL', 'RARE_METALS'],
        cbdcs: this.getCbdcTier(),
        calculatedAt: new Date(),
      },
    });

    return composition.id;
  }

  /**
   * Calculate real-time SSU composition
   */
  async calculateComposition(ssuId: string): Promise<SsuCompositionWeights> {
    // Get latest composition
    const latestComposition = await prisma.ssuComposition.findFirst({
      where: { ssuId },
      orderBy: { calculatedAt: 'desc' },
    });

    if (!latestComposition) {
      await this.initializeComposition(ssuId);
      return await this.calculateComposition(ssuId);
    }

    // Rebalance if needed
    const rebalanced = await this.rebalanceComposition(ssuId, latestComposition);

    // Calculate LAM adjustment
    const lamAdjustment = await this.calculateLamAdjustment(ssuId);

    // Apply LAM to composition
    const adjustedComposition = await this.applyLamAdjustment(
      rebalanced,
      lamAdjustment
    );

    // Save new composition
    await prisma.ssuComposition.create({
      data: {
        ssuId,
        currencyWeight: adjustedComposition.currencyWeight,
        commodityWeight: adjustedComposition.commodityWeight,
        cbdcWeight: adjustedComposition.cbdcWeight,
        lamWeight: adjustedComposition.lamWeight,
        topSovereigns: latestComposition.topSovereigns as string[],
        commodities: latestComposition.commodities as string[],
        cbdcs: latestComposition.cbdcs as string[],
        calculatedAt: new Date(),
      },
    });

    return adjustedComposition;
  }

  /**
   * Rebalance composition based on underlying asset valuations
   */
  private async rebalanceComposition(
    ssuId: string,
    currentComposition: any
  ): Promise<SsuCompositionWeights> {
    // Get underlying asset valuations
    const currencyValue = await this.valuateCurrencyTier(
      currentComposition.topSovereigns as string[]
    );
    const commodityValue = await this.valuateCommodityTier(
      currentComposition.commodities as string[]
    );
    const cbdcValue = await this.valuateCbdcTier(
      currentComposition.cbdcs as string[]
    );

    // Calculate total value
    const totalValue = currencyValue
      .plus(commodityValue)
      .plus(cbdcValue);

    if (totalValue.eq(0)) {
      // Return default weights if no value
      return {
        currencyWeight: new Decimal(0.40),
        commodityWeight: new Decimal(0.30),
        cbdcWeight: new Decimal(0.20),
        lamWeight: new Decimal(0.10),
      };
    }

    // Calculate weights based on valuations
    const currencyWeight = currencyValue.div(totalValue);
    const commodityWeight = commodityValue.div(totalValue);
    const cbdcWeight = cbdcValue.div(totalValue);

    // Normalize to ensure 90% (remaining 10% is LAM)
    const sum = currencyWeight.plus(commodityWeight).plus(cbdcWeight);
    const normalizedCurrency = currencyWeight.div(sum).mul(0.90);
    const normalizedCommodity = commodityWeight.div(sum).mul(0.90);
    const normalizedCbdc = cbdcWeight.div(sum).mul(0.90);

    return {
      currencyWeight: normalizedCurrency,
      commodityWeight: normalizedCommodity,
      cbdcWeight: normalizedCbdc,
      lamWeight: new Decimal(0.10),
    };
  }

  /**
   * Value currency tier (top 10 SCBs)
   */
  private async valuateCurrencyTier(
    topSovereigns: string[]
  ): Promise<Decimal> {
    // In production, this would fetch actual currency values
    // For now, return a default value
    return new Decimal(1000000);
  }

  /**
   * Value commodity tier
   */
  private async valuateCommodityTier(
    commodities: string[]
  ): Promise<Decimal> {
    // Get commodity prices
    let totalValue = new Decimal(0);

    for (const commodity of commodities) {
      const commodityRecord = await prisma.commodity.findFirst({
        where: {
          commodityType: commodity.toUpperCase(),
        },
      });

      if (commodityRecord) {
        // In production, would multiply by quantity
        totalValue = totalValue.plus(commodityRecord.spotPrice);
      }
    }

    return totalValue;
  }

  /**
   * Value CBDC tier
   */
  private async valuateCbdcTier(cbdcs: string[]): Promise<Decimal> {
    // In production, this would fetch CBDC values
    // For now, return a default value
    return new Decimal(500000);
  }

  /**
   * Calculate LAM (Liquidity Adjustment Mechanism) adjustment
   */
  private async calculateLamAdjustment(ssuId: string): Promise<Decimal> {
    // LAM adjusts based on liquidity conditions
    // In production, this would consider:
    // - Market liquidity
    // - Settlement volumes
    // - FX volatility
    // - Crisis indicators

    // For now, return neutral adjustment (0)
    return new Decimal(0);
  }

  /**
   * Apply LAM adjustment to composition
   */
  private async applyLamAdjustment(
    composition: SsuCompositionWeights,
    lamAdjustment: Decimal
  ): Promise<SsuCompositionWeights> {
    // Apply LAM adjustment by redistributing weights
    // The 10% LAM weight can adjust other weights during liquidity events

    // For now, return composition as-is
    return composition;
  }

  /**
   * Get top 10 sovereigns for currency tier
   */
  private getTopSovereigns(): string[] {
    // In production, this would query based on liquidity/stability metrics
    // For now, return default list
    return [
      'OMNL',
      'SOB1',
      'SOB2',
      'SOB3',
      'SOB4',
      'SOB5',
      'SOB6',
      'SOB7',
      'SOB8',
      'SOB9',
    ];
  }

  /**
   * Get CBDC tier
   */
  private getCbdcTier(): string[] {
    // In production, this would query active CBDCs
    // For now, return default list
    return ['OMDC', 'CBDC1', 'CBDC2', 'CBDC3'];
  }

  /**
   * Verify composition weights sum to 1.0
   */
  async verifyComposition(ssuId: string): Promise<boolean> {
    const composition = await prisma.ssuComposition.findFirst({
      where: { ssuId },
      orderBy: { calculatedAt: 'desc' },
    });

    if (!composition) {
      return false;
    }

    const sum = composition.currencyWeight
      .plus(composition.commodityWeight)
      .plus(composition.cbdcWeight)
      .plus(composition.lamWeight);

    // Allow small rounding differences
    return sum.gte(0.9999) && sum.lte(1.0001);
  }

  /**
   * Get latest composition for SSU
   */
  async getLatestComposition(ssuId: string) {
    return await prisma.ssuComposition.findFirst({
      where: { ssuId },
      orderBy: { calculatedAt: 'desc' },
    });
  }
}

export const ssuCompositionService = new SsuCompositionService();

