// CDT Settlement Service
// SSU derivatives settlement
// Direct exchange: CDT ↔ CBDC
// Cross-commodity swaps
// Multi-leg commodity settlements

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


export interface CdtSettlementRequest {
  cdtId: string;
  targetAssetType: string; // ssu, cbdc, commodity
  targetAssetId?: string;
  targetAmount?: string;
  sourceBankId?: string;
  destinationBankId?: string;
}

export interface CrossCommoditySwapRequest {
  sourceCdtId: string;
  targetCommodityType: string;
  targetAmount: string;
}

export class CdtSettlementService {
  /**
   * Execute CDT settlement
   */
  async executeSettlement(
    request: CdtSettlementRequest
  ): Promise<string> {
    const cdt = await prisma.commodityDigitalToken.findUnique({
      where: { cdtId: request.cdtId },
    });

    if (!cdt || cdt.status !== 'active') {
      throw new Error('CDT not found or not active');
    }

    let transactionType = 'transfer';

    // Determine settlement type
    if (request.targetAssetType === 'ssu') {
      transactionType = 'ssu_derivative';
      return await this.settleSsuDerivative(request);
    } else if (request.targetAssetType === 'cbdc') {
      transactionType = 'exchange_cbdc';
      return await this.exchangeCdtForCbdc(request);
    } else if (request.targetAssetType === 'commodity') {
      transactionType = 'cross_commodity_swap';
      return await this.executeCrossCommoditySwap({
        sourceCdtId: request.cdtId,
        targetCommodityType: request.targetAssetId || '',
        targetAmount: request.targetAmount || cdt.weight.toString(),
      });
    } else {
      throw new Error(`Unsupported target asset type: ${request.targetAssetType}`);
    }
  }

  /**
   * Settle SSU derivative
   */
  private async settleSsuDerivative(
    request: CdtSettlementRequest
  ): Promise<string> {
    const transactionId = `CDT-TX-SSU-${uuidv4()}`;

    // Create transaction
    await prisma.cdtTransaction.create({
      data: {
        transactionId,
        cdtId: request.cdtId,
        transactionType: 'ssu_derivative',
        sourceBankId: request.sourceBankId || null,
        destinationBankId: request.destinationBankId || null,
        targetAssetType: 'ssu',
        targetAssetId: request.targetAssetId || null,
        amount: new Decimal(0), // Will be calculated based on SSU value
        status: 'completed',
        completedAt: new Date(),
      },
    });

    // In production, this would:
    // 1. Calculate SSU equivalent value
    // 2. Execute SSU transfer
    // 3. Update balances

    return transactionId;
  }

  /**
   * Exchange CDT for CBDC
   */
  private async exchangeCdtForCbdc(
    request: CdtSettlementRequest
  ): Promise<string> {
    const cdt = await prisma.commodityDigitalToken.findUnique({
      where: { cdtId: request.cdtId },
      include: {
        reserveCertificate: true,
      },
    });

    if (!cdt) {
      throw new Error('CDT not found');
    }

    // Get commodity spot price
    const commodity = await prisma.commodity.findFirst({
      where: {
        commodityType: cdt.commodityType,
        unit: cdt.unit,
      },
    });

    if (!commodity) {
      throw new Error('Commodity pricing not found');
    }

    // Calculate CBDC amount (CDT weight * spot price)
    const cdtValue = cdt.weight.mul(commodity.spotPrice);
    const cbdcAmount = request.targetAmount
      ? new Decimal(request.targetAmount)
      : cdtValue;

    const transactionId = `CDT-TX-CBDC-${uuidv4()}`;

    // Create transaction
    await prisma.cdtTransaction.create({
      data: {
        transactionId,
        cdtId: request.cdtId,
        transactionType: 'exchange_cbdc',
        sourceBankId: request.sourceBankId || null,
        destinationBankId: request.destinationBankId || null,
        targetAssetType: 'cbdc',
        targetAssetId: request.targetAssetId || null,
        amount: cbdcAmount,
        status: 'completed',
        completedAt: new Date(),
      },
    });

    // In production, this would:
    // 1. Transfer CDT
    // 2. Mint/transfer CBDC
    // 3. Update balances

    return transactionId;
  }

  /**
   * Execute cross-commodity swap
   */
  async executeCrossCommoditySwap(
    request: CrossCommoditySwapRequest
  ): Promise<string> {
    const sourceCdt = await prisma.commodityDigitalToken.findUnique({
      where: { cdtId: request.sourceCdtId },
      include: {
        reserveCertificate: true,
      },
    });

    if (!sourceCdt || sourceCdt.status !== 'active') {
      throw new Error('Source CDT not found or not active');
    }

    // Get commodity prices
    const sourceCommodity = await prisma.commodity.findFirst({
      where: {
        commodityType: sourceCdt.commodityType,
        unit: sourceCdt.unit,
      },
    });

    const targetCommodity = await prisma.commodity.findFirst({
      where: {
        commodityType: request.targetCommodityType.toUpperCase(),
        unit: sourceCdt.unit, // Assume same unit
      },
    });

    if (!sourceCommodity || !targetCommodity) {
      throw new Error('Commodity pricing not found');
    }

    // Calculate swap ratio
    const sourceValue = sourceCdt.weight.mul(sourceCommodity.spotPrice);
    const targetPrice = targetCommodity.spotPrice;
    const targetWeight = sourceValue.div(targetPrice);

    const transactionId = `CDT-TX-SWAP-${uuidv4()}`;

    // Create transaction
    await prisma.cdtTransaction.create({
      data: {
        transactionId,
        cdtId: request.sourceCdtId,
        transactionType: 'cross_commodity_swap',
        targetAssetType: 'commodity',
        targetAssetId: request.targetCommodityType.toUpperCase(),
        amount: targetWeight,
        status: 'completed',
        completedAt: new Date(),
      },
    });

    // In production, this would:
    // 1. Burn source CDT
    // 2. Mint target CDT
    // 3. Update balances

    return transactionId;
  }

  /**
   * Execute multi-leg commodity settlement
   */
  async executeMultiLegSettlement(
    legs: Array<{
      cdtId: string;
      targetAssetType: string;
      targetAssetId?: string;
      amount?: string;
    }>
  ): Promise<string[]> {
    const transactionIds: string[] = [];

    try {
      // Execute all legs
      for (const leg of legs) {
        const transactionId = await this.executeSettlement({
          cdtId: leg.cdtId,
          targetAssetType: leg.targetAssetType,
          targetAssetId: leg.targetAssetId,
          targetAmount: leg.amount,
        });

        transactionIds.push(transactionId);
      }

      return transactionIds;
    } catch (error) {
      // Rollback on error
      for (const transactionId of transactionIds) {
        try {
          await prisma.cdtTransaction.update({
            where: { transactionId },
            data: {
              status: 'failed',
            },
          });
        } catch (rollbackError) {
          // Ignore rollback errors
        }
      }

      throw error;
    }
  }

  /**
   * Get CDT transactions
   */
  async getCdtTransactions(
    cdtId?: string,
    transactionType?: string,
    status?: string,
    limit: number = 100
  ) {
    return await prisma.cdtTransaction.findMany({
      where: {
        ...(cdtId && { cdtId }),
        ...(transactionType && { transactionType }),
        ...(status && { status }),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  /**
   * Get transaction by ID
   */
  async getTransaction(transactionId: string) {
    return await prisma.cdtTransaction.findUnique({
      where: { transactionId },
      include: {
        cdt: {
          include: {
            reserveCertificate: true,
          },
        },
      },
    });
  }
}

export const cdtSettlementService = new CdtSettlementService();

