// GSS Master Ledger Service
// Dual-ledger synchronization (SCB + DBIS)
// Multi-asset posting logic
// Sovereign signature validation

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

export interface GssMasterLedgerEntry {
  nodeId: string;
  sourceBankId: string;
  destinationBankId: string;
  amount: string;
  currencyCode: string;
  assetType: string;
  sovereignSignature?: string;
}

export interface DualLedgerResult {
  entryId: string;
  sovereignLedgerHash: string;
  dbisLedgerHash: string;
  dualCommit: boolean;
}

export class GssMasterLedgerService {
  /**
   * Post to GSS Master Ledger with dual-ledger synchronization
   */
  async postToMasterLedger(
    entry: GssMasterLedgerEntry
  ): Promise<DualLedgerResult> {
    const entryId = `GSS-ENTRY-${uuidv4()}`;

    try {
      // Step 1: Post to sovereign ledger (SCB)
      const sovereignHash = await this.postToSovereignLedger(entry);

      // Step 2: Post to DBIS master ledger
      const dbisHash = await this.postToDBISMasterLedger(entry);

      // Step 3: Validate sovereign signature if provided
      if (entry.sovereignSignature) {
        await this.validateSovereignSignature(entry);
      }

      // Step 4: Create master ledger entry
      const masterEntry = await prisma.gssMasterLedger.create({
        data: {
          entryId,
          nodeId: entry.nodeId,
          sourceBankId: entry.sourceBankId,
          destinationBankId: entry.destinationBankId,
          amount: new Decimal(entry.amount),
          currencyCode: entry.currencyCode,
          assetType: entry.assetType,
          sovereignSignature: entry.sovereignSignature || null,
          dualLedgerCommit: true,
          sovereignLedgerHash: sovereignHash,
          dbisLedgerHash: dbisHash,
          status: 'settled',
          committedAt: new Date(),
          settledAt: new Date(),
        },
      });

      return {
        entryId: masterEntry.entryId,
        sovereignLedgerHash: sovereignHash,
        dbisLedgerHash: dbisHash,
        dualCommit: true,
      };
    } catch (error) {
      // Create failed entry
      await prisma.gssMasterLedger.create({
        data: {
          entryId,
          nodeId: entry.nodeId,
          sourceBankId: entry.sourceBankId,
          destinationBankId: entry.destinationBankId,
          amount: new Decimal(entry.amount),
          currencyCode: entry.currencyCode,
          assetType: entry.assetType,
          dualLedgerCommit: false,
          status: 'failed',
        },
      });

      throw error;
    }
  }

  /**
   * Post to sovereign ledger (SCB side)
   */
  private async postToSovereignLedger(
    entry: GssMasterLedgerEntry
  ): Promise<string> {
    // Get accounts
    const sourceAccounts = await prisma.bankAccount.findMany({
      where: {
        sovereignBankId: entry.sourceBankId,
        currencyCode: entry.currencyCode,
        assetType: entry.assetType,
        status: 'active',
      },
      take: 1,
    });

    const destAccounts = await prisma.bankAccount.findMany({
      where: {
        sovereignBankId: entry.destinationBankId,
        currencyCode: entry.currencyCode,
        assetType: entry.assetType,
        status: 'active',
      },
      take: 1,
    });

    if (sourceAccounts.length === 0 || destAccounts.length === 0) {
      throw new Error('Accounts not found for sovereign ledger posting');
    }

    // Post to sovereign ledger
    const ledgerId = `Sovereign_${entry.sourceBankId}`;
    const result = await ledgerService.postDoubleEntry(
      ledgerId,
      sourceAccounts[0].id,
      destAccounts[0].id,
      entry.amount,
      entry.currencyCode,
      entry.assetType as any,
      'Type_A',
      uuidv4(),
      undefined,
      { gssEntry: true }
    );

    // Get block hash
    const ledgerEntry = await prisma.ledgerEntry.findUnique({
      where: { id: result.entryIds[0] },
    });

    return ledgerEntry?.blockHash || '';
  }

  /**
   * Post to DBIS master ledger
   */
  private async postToDBISMasterLedger(
    entry: GssMasterLedgerEntry
  ): Promise<string> {
    // Get accounts
    const sourceAccounts = await prisma.bankAccount.findMany({
      where: {
        sovereignBankId: entry.sourceBankId,
        currencyCode: entry.currencyCode,
        assetType: entry.assetType,
        status: 'active',
      },
      take: 1,
    });

    const destAccounts = await prisma.bankAccount.findMany({
      where: {
        sovereignBankId: entry.destinationBankId,
        currencyCode: entry.currencyCode,
        assetType: entry.assetType,
        status: 'active',
      },
      take: 1,
    });

    if (sourceAccounts.length === 0 || destAccounts.length === 0) {
      throw new Error('Accounts not found for DBIS master ledger posting');
    }

    // Post to DBIS master ledger
    const result = await ledgerService.postDoubleEntry(
      'Master',
      sourceAccounts[0].id,
      destAccounts[0].id,
      entry.amount,
      entry.currencyCode,
      entry.assetType as any,
      'Type_A',
      uuidv4(),
      undefined,
      { gssEntry: true, masterLedger: true }
    );

    // Get block hash
    const ledgerEntry = await prisma.ledgerEntry.findUnique({
      where: { id: result.entryIds[0] },
    });

    return ledgerEntry?.blockHash || '';
  }

  /**
   * Validate sovereign signature
   */
  private async validateSovereignSignature(
    entry: GssMasterLedgerEntry
  ): Promise<boolean> {
    // In production, this would validate against HSM-stored keys
    // For now, we just verify the signature exists
    if (!entry.sovereignSignature) {
      return false;
    }

    // Get sovereign identity
    const identity = await prisma.sovereignIdentity.findFirst({
      where: {
        sovereignBankId: entry.sourceBankId,
        identityType: 'Settlement',
        status: 'active',
      },
    });

    if (!identity) {
      throw new Error('Sovereign identity not found');
    }

    // Signature validation would happen here with HSM
    return true;
  }

  /**
   * Get master ledger entries
   */
  async getMasterLedgerEntries(
    nodeId?: string,
    status?: string,
    limit: number = 100
  ) {
    return await prisma.gssMasterLedger.findMany({
      where: {
        ...(nodeId && { nodeId }),
        ...(status && { status }),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  /**
   * Get entry by ID
   */
  async getMasterLedgerEntry(entryId: string) {
    return await prisma.gssMasterLedger.findUnique({
      where: { entryId },
    });
  }

  /**
   * Verify dual-ledger synchronization
   */
  async verifyDualLedgerSync(entryId: string): Promise<boolean> {
    const entry = await prisma.gssMasterLedger.findUnique({
      where: { entryId },
    });

    if (!entry) {
      return false;
    }

    // Verify both ledger hashes exist
    if (!entry.sovereignLedgerHash || !entry.dbisLedgerHash) {
      return false;
    }

    // Verify both ledgers have matching entries
    const sovereignEntry = await prisma.ledgerEntry.findFirst({
      where: { blockHash: entry.sovereignLedgerHash },
    });

    const dbisEntry = await prisma.ledgerEntry.findFirst({
      where: { blockHash: entry.dbisLedgerHash },
    });

    return !!(sovereignEntry && dbisEntry && entry.dualLedgerCommit);
  }
}

export const gssMasterLedgerService = new GssMasterLedgerService();

