// GDSL Settlement Service
// Multi-ledger settlement with hash-lock finality

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';
import { gssMasterLedgerService } from '@/core/settlement/gss/gss-master-ledger.service';


export interface DerivativeSettlementRequest {
  contractId: string;
  settlementAmount: string;
  currencyCode: string;
  assetType: string; // fiat, cbdc, commodity, security
  sourceBankId: string;
  destinationBankId: string;
  nodeId: string;
}

export interface SettlementResult {
  settlementId: string;
  hashLock: string;
  sovereignLedgerHash?: string;
  dbisLedgerHash?: string;
  status: string;
}

export class GdslSettlementService {
  /**
   * Execute derivative settlement
   */
  async executeSettlement(
    request: DerivativeSettlementRequest
  ): Promise<SettlementResult> {
    const settlementId = `DSETTLE-${uuidv4()}`;

    // Verify contract exists and is active
    const contract = await prisma.derivative_contracts.findUnique({
      where: { contractId: request.contractId },
    });

    if (!contract) {
      throw new Error(`Derivative contract not found: ${request.contractId}`);
    }

    if (contract.status !== 'active') {
      throw new Error(`Contract is not active: ${contract.status}`);
    }

    // Generate hash-lock
    const hashLock = this.generateHashLock(
      request.contractId,
      request.settlementAmount,
      request.sourceBankId,
      request.destinationBankId
    );

    // Create settlement record
    const settlement = await prisma.derivative_settlements.create({
      data: {
        id: uuidv4(),
        settlementId,
        contractId: request.contractId,
        settlementAmount: new Decimal(request.settlementAmount),
        currencyCode: request.currencyCode,
        assetType: request.assetType,
        hashLock,
        status: 'pending',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });

    // Post to GSS Master Ledger for dual-ledger settlement
    try {
      const ledgerResult = await gssMasterLedgerService.postToMasterLedger({
        nodeId: request.nodeId,
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: request.settlementAmount,
        currencyCode: request.currencyCode,
        assetType: request.assetType,
      });

      // Update settlement with ledger hashes
      await prisma.derivative_settlements.update({
        where: { settlementId },
        data: {
          sovereignLedgerHash: ledgerResult.sovereignLedgerHash,
          dbisLedgerHash: ledgerResult.dbisLedgerHash,
          dualLedgerCommit: ledgerResult.dualCommit,
          status: 'committed',
          committedAt: new Date(),
        },
      });

      // Finalize settlement
      await this.finalizeSettlement(settlementId);

      return {
        settlementId: settlement.settlementId,
        hashLock: settlement.hashLock ?? undefined,
        sovereignLedgerHash: ledgerResult.sovereignLedgerHash ?? undefined,
        dbisLedgerHash: ledgerResult.dbisLedgerHash ?? undefined,
        status: 'settled',
      };
    } catch (error) {
      // Mark settlement as failed
      await prisma.derivative_settlements.update({
        where: { settlementId },
        data: {
          status: 'failed',
        },
      });

      throw error;
    }
  }

  /**
   * Generate hash-lock for finality
   * hashLock = SHA3(contractId + settlementAmount + sourceBankId + destinationBankId)
   */
  private generateHashLock(
    contractId: string,
    settlementAmount: string,
    sourceBankId: string,
    destinationBankId: string
  ): string {
    const data = `${contractId}:${settlementAmount}:${sourceBankId}:${destinationBankId}`;
    const hash = createHash('sha3-256').update(data).digest('hex');
    return hash;
  }

  /**
   * Finalize settlement (enforce finality)
   */
  async finalizeSettlement(settlementId: string): Promise<void> {
    const settlement = await prisma.derivative_settlements.findUnique({
      where: { settlementId },
    });

    if (!settlement) {
      throw new Error(`Settlement not found: ${settlementId}`);
    }

    if (settlement.status !== 'committed') {
      throw new Error(`Settlement must be committed before finalization: ${settlement.status}`);
    }

    // Update to final status
    await prisma.derivative_settlements.update({
      where: { settlementId },
      data: {
        status: 'final',
        settledAt: new Date(),
        finalizedAt: new Date(),
      },
    });
  }

  /**
   * Verify hash-lock
   */
  async verifyHashLock(
    settlementId: string,
    expectedHashLock: string
  ): Promise<boolean> {
    const settlement = await prisma.derivative_settlements.findUnique({
      where: { settlementId },
    });

    if (!settlement) {
      return false;
    }

    return settlement.hashLock === expectedHashLock;
  }

  /**
   * Get settlement status
   */
  async getSettlementStatus(settlementId: string): Promise<string | null> {
    const settlement = await prisma.derivative_settlements.findUnique({
      where: { settlementId },
      select: { status: true },
    });

    return settlement?.status || null;
  }
}

export const gdslSettlementService = new GdslSettlementService();

