// GAS Settlement Service
// Multi-dimensional atomic settlement with commit matching

import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';
import { atomicSettlementService } from '@/core/settlement/isn/atomic-settlement.service';
import { gasCommitmentService } from './gas-commitment.service';
import { gasRoutingService } from './gas-routing.service';
import { logger } from '@/infrastructure/monitoring/logger';
import prisma from '@/shared/database/prisma';

export interface GasSettlementRequest {
  sourceBankId: string;
  destinationBankId: string;
  amount: number;
  currencyCode: string;
  assetType: string;
  networkType?: 'classical' | 'cbdc' | 'commodity' | 'security' | 'quantum' | 'multiversal';
  fxRate?: number;
  assetDetails?: any;
  temporalState?: any;
  optimizeFor?: 'cost' | 'latency' | 'dimensional_alignment';
  transactionId?: string;
}

export interface GasSettlementResult {
  settlementId: string;
  gasSettlementId: string;
  status: string;
  commitmentHash: string;
  routeId: string;
  settlementTime: number;
  allCommitsMatched: boolean;
}

export class GasSettlementService {
  /**
   * Execute GAS atomic settlement
   * Settlement only final when all commits match across dimensions
   */
  async executeGasSettlement(
    request: GasSettlementRequest
  ): Promise<GasSettlementResult> {
    const startTime = Date.now();
    const settlementId = uuidv4();
    const gasSettlementId = `GAS-${uuidv4()}`;

    logger.info('GAS: Starting multi-dimensional atomic settlement', {
      gasSettlementId,
      request,
    });

    try {
      // Step 1: Calculate optimal route
      const routingResult = await gasRoutingService.calculateOptimalRoute({
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: request.amount.toString(),
        currencyCode: request.currencyCode,
        assetType: request.assetType,
        networkType: request.networkType,
        optimizeFor: request.optimizeFor,
      });

      // Step 2: Create multi-dimensional commitment
      const commitmentResult =
        await gasCommitmentService.createMultiDimensionalCommitment({
          settlementId,
          sourceBankId: request.sourceBankId,
          destinationBankId: request.destinationBankId,
          amount: request.amount,
          currencyCode: request.currencyCode,
          assetType: request.assetType,
          fxRate: request.fxRate,
          assetDetails: request.assetDetails,
          temporalState: request.temporalState,
        });

      // Step 3: Execute base atomic settlement (extends existing service)
      const atomicResult = await atomicSettlementService.executeAtomicSettlement(
        {
          sourceBankId: request.sourceBankId,
          destinationBankId: request.destinationBankId,
          amount: request.amount,
          currencyCode: request.currencyCode,
          assetType: request.assetType,
          transactionId: request.transactionId,
        }
      );

      // Step 4: Verify all commits match
      const verificationResult =
        await gasCommitmentService.verifyAllCommitsMatch(settlementId);

      if (!verificationResult.verified) {
        throw new Error(
          `Commit verification failed: ${verificationResult.missingCommits.join(', ')}`
        );
      }

      // Step 5: Update commitment with settlement reference
      await prisma.gas_commitments.updateMany({
        where: { settlementId },
        data: { settlementId: atomicResult.settlementId },
      });

      // Step 6: Update routing decision with settlement reference
      await prisma.gas_routing_decisions.updateMany({
        where: { routeId: routingResult.routeId },
        data: { settlementId: atomicResult.settlementId },
      });

      // Step 7: Create GAS settlement record
      const settlementTime = Date.now() - startTime;

      const gasSettlement = await prisma.gas_settlements.create({
        data: {
          id: uuidv4(),
          gasSettlementId,
          settlementId: atomicResult.settlementId,
          sourceBankId: request.sourceBankId,
          destinationBankId: request.destinationBankId,
          amount: new Decimal(request.amount),
          currencyCode: request.currencyCode,
          assetType: request.assetType,
          networkType: request.networkType || 'classical',
          commitmentHash: commitmentResult.commitmentHash,
          routeId: routingResult.routeId,
          routingEngine: routingResult.routingEngine,
          fxCommit: commitmentResult.commitments.fxCommit || null,
          assetCommit: commitmentResult.commitments.assetCommit || null,
          temporalState: commitmentResult.commitments.temporalState || null,
          dimensionalAlignment: routingResult.dimensionalAlignment,
          settlementTime,
          status: 'settled',
          allCommitsMatched: true,
          settledAt: new Date(),
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      });

      logger.info('GAS: Multi-dimensional atomic settlement completed', {
        gasSettlementId,
        settlementTime,
      });

      return {
        settlementId: atomicResult.settlementId,
        gasSettlementId,
        status: 'settled',
        commitmentHash: commitmentResult.commitmentHash,
        routeId: routingResult.routeId,
        settlementTime,
        allCommitsMatched: true,
      };
    } catch (error) {
      logger.error('GAS: Settlement failed', {
        gasSettlementId,
        error: error instanceof Error ? error.message : String(error),
      });

      // Create failed settlement record
      // Generate a placeholder commitment hash for failed settlements
      const failedCommitmentHash = createHash('sha256')
        .update(`${gasSettlementId}-failed-${Date.now()}`)
        .digest('hex');
      
      await prisma.gas_settlements.create({
        data: {
          id: uuidv4(),
          gasSettlementId,
          settlementId: null,
          sourceBankId: request.sourceBankId,
          destinationBankId: request.destinationBankId,
          amount: new Decimal(request.amount),
          currencyCode: request.currencyCode,
          assetType: request.assetType,
          networkType: request.networkType || 'classical',
          commitmentHash: failedCommitmentHash,
          status: 'failed',
          allCommitsMatched: false,
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      });

      throw error;
    }
  }

  /**
   * Get GAS settlement by ID
   */
  async getGasSettlement(gasSettlementId: string) {
    return await prisma.gas_settlements.findUnique({
      where: { gasSettlementId },
      include: {
        gas_commitments: true,
        gas_routing_decisions: true,
      },
    });
  }

  /**
   * Get GAS settlements for a bank
   */
  async getGasSettlementsForBank(
    sovereignBankId: string,
    limit: number = 100
  ) {
    return await prisma.gas_settlements.findMany({
      where: {
        OR: [
          { sourceBankId: sovereignBankId },
          { destinationBankId: sovereignBankId },
        ],
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
      include: {
        gas_commitments: true,
        gas_routing_decisions: true,
      },
    });
  }

  /**
   * Get GAS settlements by network type
   */
  async getGasSettlementsByNetworkType(
    networkType: string,
    limit: number = 100
  ) {
    return await prisma.gas_settlements.findMany({
      where: { networkType },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  /**
   * Check if settlement is atomic and all commits matched
   */
  async isSettlementAtomicAndVerified(
    gasSettlementId: string
  ): Promise<boolean> {
    const settlement = await prisma.gas_settlements.findUnique({
      where: { gasSettlementId },
    });

    if (!settlement) {
      return false;
    }

    return (
      settlement.status === 'settled' &&
      settlement.allCommitsMatched === true &&
      settlement.settlementTime !== null &&
      settlement.settlementTime < 1000 // Atomic within 1 second
    );
  }
}

export const gasSettlementService = new GasSettlementService();

