// SSU Service
// SSU mint/burn lifecycle
// SSU smart token issuance
// Atomic settlement using SSU
// SSU redemption and recycling

import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { ssuCompositionService } from './ssu-composition.service';
import { ssuTransactionService } from './ssu-transaction.service';
import prisma from '@/shared/database/prisma';

export interface SsuMintRequest {
  amount: string;
  triggerBankId?: string;
  transactionId?: string;
}

export interface SsuBurnRequest {
  ssuId: string;
  amount: string;
  reason?: string;
}

export interface SsuSettlementRequest {
  ssuId: string;
  sourceBankId: string;
  destinationBankId: string;
  amount: string;
}

export interface SsuRedemptionRequest {
  ssuId: string;
  sovereignBankId: string;
  amount: string;
  targetAssetType: string;
  targetCurrencyCode?: string;
}

export class SsuService {
  /**
   * Mint SSU
   */
  async mintSsu(request: SsuMintRequest): Promise<string> {
    // Get or create default SSU
    const ssu = await this.getOrCreateDefaultSsu();

    // Verify liquidity for minting
    await this.verifyLiquidityForMinting(request.amount);

    // Calculate composition
    const composition = await ssuCompositionService.calculateComposition(ssu.ssuId);

    // Create mint transaction
    const transactionId = await ssuTransactionService.createTransaction({
      ssuId: ssu.ssuId,
      transactionType: 'mint',
      amount: request.amount,
      sourceBankId: request.triggerBankId,
      settlementId: request.transactionId,
    });

    // Update SSU balance (if tracked)
    // In a real implementation, this would update a balance field

    return transactionId;
  }

  /**
   * Burn SSU
   */
  async burnSsu(request: SsuBurnRequest): Promise<string> {
    const ssu = await prisma.syntheticSettlementUnit.findUnique({
      where: { ssuId: request.ssuId },
    });

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

    // Create burn transaction
    const transactionId = await ssuTransactionService.createTransaction({
      ssuId: request.ssuId,
      transactionType: 'burn',
      amount: request.amount,
    });

    // Update SSU balance
    // In a real implementation, this would update a balance field

    return transactionId;
  }

  /**
   * Execute atomic settlement using SSU
   */
  async executeAtomicSettlement(
    request: SsuSettlementRequest
  ): Promise<string> {
    const ssu = await prisma.syntheticSettlementUnit.findUnique({
      where: { ssuId: request.ssuId },
    });

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

    // Verify sufficient SSU balance
    // In a real implementation, this would check actual balance

    // Create settlement transaction
    const transactionId = await ssuTransactionService.createTransaction({
      ssuId: request.ssuId,
      transactionType: 'settle',
      amount: request.amount,
      sourceBankId: request.sourceBankId,
      destinationBankId: request.destinationBankId,
    });

    // Execute atomic swap
    // In a real implementation, this would interact with the atomic settlement service

    return transactionId;
  }

  /**
   * Redeem SSU
   */
  async redeemSsu(request: SsuRedemptionRequest): Promise<string> {
    const ssu = await prisma.syntheticSettlementUnit.findUnique({
      where: { ssuId: request.ssuId },
    });

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

    // Create redemption request
    const redemptionRequest = await prisma.ssuRedemptionRequest.create({
      data: {
        requestId: `SSU-REDEEM-${uuidv4()}`,
        ssuId: request.ssuId,
        sovereignBankId: request.sovereignBankId,
        amount: new Decimal(request.amount),
        targetAssetType: request.targetAssetType,
        targetCurrencyCode: request.targetCurrencyCode || null,
        status: 'pending',
      },
    });

    // Process redemption
    await this.processRedemption(redemptionRequest.requestId);

    return redemptionRequest.requestId;
  }

  /**
   * Recycle SSU
   */
  async recycleSsu(ssuId: string, amount: string): Promise<string> {
    const ssu = await prisma.syntheticSettlementUnit.findUnique({
      where: { ssuId },
    });

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

    // Create recycle transaction
    const transactionId = await ssuTransactionService.createTransaction({
      ssuId,
      transactionType: 'recycle',
      amount,
    });

    return transactionId;
  }

  /**
   * Get or create default SSU
   */
  private async getOrCreateDefaultSsu() {
    let ssu = await prisma.syntheticSettlementUnit.findFirst({
      where: {
        ssuName: 'DBIS Global SSU',
        status: 'active',
      },
    });

    if (!ssu) {
      ssu = await prisma.syntheticSettlementUnit.create({
        data: {
          ssuId: `SSU-${uuidv4()}`,
          ssuName: 'DBIS Global SSU',
          description: 'DBIS Synthetic Settlement Unit - Global settlement asset',
          underlyingAssets: [],
          status: 'active',
        },
      });

      // Initialize composition
      await ssuCompositionService.initializeComposition(ssu.ssuId);
    }

    return ssu;
  }

  /**
   * Verify liquidity for minting
   */
  private async verifyLiquidityForMinting(amount: string): Promise<void> {
    // In production, this would verify that underlying assets have sufficient liquidity
    // For now, we assume liquidity is available
    const amountDecimal = new Decimal(amount);

    if (amountDecimal.lte(0)) {
      throw new Error('Mint amount must be greater than zero');
    }
  }

  /**
   * Process redemption request
   */
  private async processRedemption(requestId: string): Promise<void> {
    const request = await prisma.ssuRedemptionRequest.findUnique({
      where: { requestId },
    });

    if (!request || request.status !== 'pending') {
      return;
    }

    try {
      // Convert SSU to target asset
      // In production, this would perform actual conversion

      // Update request status
      await prisma.ssuRedemptionRequest.update({
        where: { requestId },
        data: {
          status: 'processed',
          processedAt: new Date(),
        },
      });

      // Create redemption transaction
      await ssuTransactionService.createTransaction({
        ssuId: request.ssuId,
        transactionType: 'redeem',
        amount: request.amount.toString(),
        sourceBankId: request.sovereignBankId,
      });
    } catch (error) {
      await prisma.ssuRedemptionRequest.update({
        where: { requestId },
        data: {
          status: 'rejected',
        },
      });

      throw error;
    }
  }

  /**
   * Get SSU by ID
   */
  async getSsu(ssuId: string) {
    return await prisma.syntheticSettlementUnit.findUnique({
      where: { ssuId },
      include: {
        compositions: {
          orderBy: { calculatedAt: 'desc' },
          take: 1,
        },
      },
    });
  }

  /**
   * List active SSUs
   */
  async listActiveSsus() {
    return await prisma.syntheticSettlementUnit.findMany({
      where: {
        status: 'active',
      },
    });
  }
}

export const ssuService = new SsuService();

