// GRU Liquidity Loop Service
// Atomic transaction loop: 7 → 10 GRU → 9.55 (net after FX)
// Re-run until value reaches target

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { logger } from '@/infrastructure/monitoring/logger';
import { gasSettlementService } from '@/core/settlement/gas/gas-settlement.service';


export interface GruLiquidityLoopRequest {
  sourceBankId: string;
  destinationBankId: string;
  initialAmount: string; // e.g., 7 GRU
  targetAmount: string; // e.g., 10 GRU
  targetNetValue: string; // e.g., 9.55 (net after FX)
  maxIterations?: number;
}

export interface GruLiquidityLoopResult {
  loopId: string;
  iterations: number;
  finalAmount: Decimal;
  finalNetValue: Decimal;
  targetReached: boolean;
  transactions: string[];
}

export class GruLiquidityLoopService {
  /**
   * Execute GRU liquidity loop
   * 7 → 10 GRU → 9.55 (net after FX)
   * Re-run until value reaches target
   */
  async executeLiquidityLoop(
    request: GruLiquidityLoopRequest
  ): Promise<GruLiquidityLoopResult> {
    logger.info('GRU: Starting liquidity loop', { request });

    const loopId = `GRU-LOOP-${uuidv4()}`;
    const maxIterations = request.maxIterations || 10;
    const targetAmount = new Decimal(request.targetAmount);
    const targetNetValue = new Decimal(request.targetNetValue);

    let currentAmount = new Decimal(request.initialAmount);
    let iterations = 0;
    const transactions: string[] = [];
    let targetReached = false;

    // Create loop record
    await prisma.gru_liquidity_loops.create({
      data: {
        loopId,
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        initialAmount: currentAmount,
        targetAmount,
        targetNetValue,
        status: 'running',
      },
    });

    while (iterations < maxIterations && !targetReached) {
      iterations++;

      logger.info('GRU: Liquidity loop iteration', {
        loopId,
        iteration: iterations,
        currentAmount: currentAmount.toString(),
      });

      // Step 1: Execute atomic transaction via GAS
      const settlementResult = await gasSettlementService.executeGasSettlement({
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: currentAmount.toNumber(),
        currencyCode: 'GRU',
        assetType: 'gru',
        networkType: 'classical',
      });

      transactions.push(settlementResult.gasSettlementId);

      // Step 2: Calculate net value after FX
      // In this example: 10 GRU → 9.55 net (FX cost = 0.45)
      const fxCost = new Decimal(0.045); // 4.5% FX cost
      const netValue = currentAmount.times(new Decimal(1).minus(fxCost));

      // Step 3: Update current amount (re-invest net value)
      currentAmount = netValue;

      // Step 4: Check if target reached
      if (
        currentAmount.gte(targetAmount) ||
        netValue.gte(targetNetValue)
      ) {
        targetReached = true;
        logger.info('GRU: Liquidity loop target reached', {
          loopId,
          iterations,
          finalAmount: currentAmount.toString(),
          finalNetValue: netValue.toString(),
        });
        break;
      }

      // Step 5: Update loop record
      await prisma.gru_liquidity_loops.update({
        where: { loopId },
        data: {
          currentAmount,
          currentNetValue: netValue,
          iterations,
          lastTransactionId: settlementResult.gasSettlementId,
        },
      });
    }

    // Finalize loop
    const finalNetValue = currentAmount.times(new Decimal(1).minus(new Decimal(0.045)));

    await prisma.gru_liquidity_loops.update({
      where: { loopId },
      data: {
        finalAmount: currentAmount,
        finalNetValue,
        iterations,
        targetReached,
        status: targetReached ? 'completed' : 'max_iterations_reached',
        completedAt: new Date(),
      },
    });

    logger.info('GRU: Liquidity loop completed', {
      loopId,
      iterations,
      targetReached,
    });

    return {
      loopId,
      iterations,
      finalAmount: currentAmount,
      finalNetValue: finalNetValue,
      targetReached,
      transactions,
    };
  }

  /**
   * Get liquidity loop by ID
   */
  async getLiquidityLoop(loopId: string) {
    return await prisma.gru_liquidity_loops.findUnique({
      where: { loopId },
    });
  }

  /**
   * Get liquidity loops for a bank
   */
  async getLiquidityLoopsForBank(sovereignBankId: string) {
    return await prisma.gru_liquidity_loops.findMany({
      where: {
        OR: [
          { sourceBankId: sovereignBankId },
          { destinationBankId: sovereignBankId },
        ],
      },
      orderBy: { createdAt: 'desc' },
    });
  }
}

export const gruLiquidityLoopService = new GruLiquidityLoopService();

