// AIFX Engine Service
// FX matching with NCE/CASO integration

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { AifxTrade } from '@/shared/types';
import { AifxPricingService } from './aifx-pricing.service';

const pricingService = new AifxPricingService();

export interface CreateAifxTradeRequest {
  corridorId: string;
  sovereignBankId: string;
  baseCurrency: string;
  quoteCurrency: string;
  amount: string;
  settlementMode?: string;
}

export interface AifxTradeResult {
  tradeId: string;
  fxPrice: string;
  totalAmount: string;
  status: string;
}

export class AifxEngineService {
  /**
   * Execute an interplanetary FX trade
   */
  async executeTrade(
    request: CreateAifxTradeRequest
  ): Promise<AifxTradeResult> {
    // Verify corridor exists
    const corridor = await prisma.aifxCorridor.findUnique({
      where: { corridorId: request.corridorId },
    });

    if (!corridor) {
      throw new Error(`Corridor not found: ${request.corridorId}`);
    }

    // Verify sovereign bank exists
    const bank = await prisma.sovereignBank.findUnique({
      where: { id: request.sovereignBankId },
    });

    if (!bank) {
      throw new Error(`Sovereign bank not found: ${request.sovereignBankId}`);
    }

    // Calculate FX price
    const pricing = await pricingService.calculateFxPrice({
      corridorId: request.corridorId,
      baseAmount: request.amount,
      pricingMethod: 'hybrid', // Use hybrid NCE/CASO
    });

    // Calculate total quote amount
    const baseAmount = new Decimal(request.amount);
    const totalQuoteAmount = baseAmount.mul(new Decimal(pricing.totalPrice));

    // Create trade
    const tradeId = `AIFX-${uuidv4()}`;
    const trade = await prisma.aifxTrade.create({
      data: {
        tradeId,
        corridorId: request.corridorId,
        sovereignBankId: request.sovereignBankId,
        baseCurrency: request.baseCurrency,
        quoteCurrency: request.quoteCurrency,
        amount: baseAmount,
        fxPrice: new Decimal(pricing.totalPrice),
        liquidityWeight: new Decimal(pricing.liquidityWeight),
        gravityFactor: new Decimal(pricing.gravityFactor),
        latencyCost: new Decimal(pricing.latencyCost),
        timeDilationIndex: new Decimal(pricing.timeDilationIndex),
        ssuStability: pricing.ssuStability ? new Decimal(pricing.ssuStability) : null,
        settlementMode: request.settlementMode || 'atomic',
        status: 'pending',
      },
    });

    // Execute trade (update status)
    await prisma.aifxTrade.update({
      where: { tradeId },
      data: {
        status: 'executed',
        executedAt: new Date(),
      },
    });

    return {
      tradeId: trade.tradeId,
      fxPrice: pricing.totalPrice,
      totalAmount: totalQuoteAmount.toString(),
      status: 'executed',
    };
  }

  /**
   * Get trade by ID
   */
  async getTrade(tradeId: string): Promise<AifxTrade | null> {
    const trade = await prisma.aifxTrade.findUnique({
      where: { tradeId },
      include: {
        corridor: true,
        sovereignBank: true,
      },
    });

    if (!trade) {
      return null;
    }

    return {
      tradeId: trade.tradeId,
      corridorId: trade.corridorId,
      sovereignBankId: trade.sovereignBankId,
      baseCurrency: trade.baseCurrency,
      quoteCurrency: trade.quoteCurrency,
      amount: trade.amount.toString(),
      fxPrice: trade.fxPrice.toString(),
      liquidityWeight: trade.liquidityWeight.toString(),
      gravityFactor: trade.gravityFactor.toString(),
      latencyCost: trade.latencyCost.toString(),
      timeDilationIndex: trade.timeDilationIndex.toString(),
      ssuStability: trade.ssuStability?.toString(),
      settlementMode: trade.settlementMode,
      status: trade.status,
    };
  }

  /**
   * Get trades for a sovereign bank
   */
  async getTradesBySovereign(
    sovereignBankId: string,
    limit = 100
  ): Promise<AifxTrade[]> {
    const trades = await prisma.aifxTrade.findMany({
      where: { sovereignBankId },
      orderBy: { executedAt: 'desc' },
      take: limit,
      include: {
        corridor: true,
      },
    });

    return trades.map((trade) => ({
      tradeId: trade.tradeId,
      corridorId: trade.corridorId,
      sovereignBankId: trade.sovereignBankId,
      baseCurrency: trade.baseCurrency,
      quoteCurrency: trade.quoteCurrency,
      amount: trade.amount.toString(),
      fxPrice: trade.fxPrice.toString(),
      liquidityWeight: trade.liquidityWeight.toString(),
      gravityFactor: trade.gravityFactor.toString(),
      latencyCost: trade.latencyCost.toString(),
      timeDilationIndex: trade.timeDilationIndex.toString(),
      ssuStability: trade.ssuStability?.toString(),
      settlementMode: trade.settlementMode,
      status: trade.status,
    }));
  }

  /**
   * Settle trade
   */
  async settleTrade(tradeId: string): Promise<void> {
    await prisma.aifxTrade.update({
      where: { tradeId },
      data: {
        status: 'settled',
        settledAt: new Date(),
      },
    });
  }
}

