// GAS Commitment Service
// Multi-commit verification across dimensions

import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';
import prisma from '@/shared/database/prisma';

export interface GasCommitment {
  scbCommit: string;
  dbisCommit: string;
  fxCommit?: string;
  assetCommit?: string;
  temporalState?: string;
}

export interface GasCommitmentRequest {
  settlementId: string;
  sourceBankId: string;
  destinationBankId: string;
  amount: number;
  currencyCode: string;
  assetType: string;
  fxRate?: number;
  assetDetails?: any;
  temporalState?: any;
}

export class GasCommitmentService {
  /**
   * Create multi-dimensional commitment
   * atomic_settlement = HASH(scb_commit, dbis_commit, fx_commit, asset_commit, temporal_state)
   */
  async createMultiDimensionalCommitment(
    request: GasCommitmentRequest
  ): Promise<{ commitmentHash: string; commitments: GasCommitment }> {
    // Step 1: Create SCB commit
    const scbCommit = await this.createScbCommit(request);

    // Step 2: Create DBIS commit
    const dbisCommit = await this.createDbisCommit(request);

    // Step 3: Create FX commit (if applicable)
    const fxCommit = request.fxRate
      ? await this.createFxCommit(request)
      : undefined;

    // Step 4: Create asset commit (if applicable)
    const assetCommit = request.assetDetails
      ? await this.createAssetCommit(request)
      : undefined;

    // Step 5: Create temporal state commit (if applicable)
    const temporalState = request.temporalState
      ? await this.createTemporalStateCommit(request)
      : undefined;

    const commitments: GasCommitment = {
      scbCommit,
      dbisCommit,
      fxCommit,
      assetCommit,
      temporalState,
    };

    // Step 6: Create atomic settlement hash
    const commitmentHash = this.hashCommitments(commitments);

    // Save commitment record
    await prisma.gas_commitments.create({
      data: {
        id: uuidv4(),
        commitmentId: `GAS-COMMIT-${uuidv4()}`,
        settlementId: request.settlementId,
        scbCommit,
        dbisCommit,
        fxCommit: fxCommit || null,
        assetCommit: assetCommit || null,
        temporalState: temporalState || null,
        commitmentHash,
        status: 'pending',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });

    return { commitmentHash, commitments };
  }

  /**
   * Create SCB commit
   */
  private async createScbCommit(
    request: GasCommitmentRequest
  ): Promise<string> {
    const commitData = {
      type: 'scb_commit',
      settlementId: request.settlementId,
      sourceBankId: request.sourceBankId,
      destinationBankId: request.destinationBankId,
      amount: request.amount,
      currencyCode: request.currencyCode,
      assetType: request.assetType,
      timestamp: new Date().toISOString(),
    };

    const commitString = JSON.stringify(commitData);
    return createHash('sha3-256').update(commitString).digest('hex');
  }

  /**
   * Create DBIS commit
   */
  private async createDbisCommit(
    request: GasCommitmentRequest
  ): Promise<string> {
    const commitData = {
      type: 'dbis_commit',
      settlementId: request.settlementId,
      sourceBankId: request.sourceBankId,
      destinationBankId: request.destinationBankId,
      amount: request.amount,
      currencyCode: request.currencyCode,
      assetType: request.assetType,
      timestamp: new Date().toISOString(),
    };

    const commitString = JSON.stringify(commitData);
    return createHash('sha3-256').update(commitString).digest('hex');
  }

  /**
   * Create FX commit
   */
  private async createFxCommit(
    request: GasCommitmentRequest
  ): Promise<string> {
    const commitData = {
      type: 'fx_commit',
      settlementId: request.settlementId,
      fxRate: request.fxRate,
      baseCurrency: request.currencyCode,
      timestamp: new Date().toISOString(),
    };

    const commitString = JSON.stringify(commitData);
    return createHash('sha3-256').update(commitString).digest('hex');
  }

  /**
   * Create asset commit
   */
  private async createAssetCommit(
    request: GasCommitmentRequest
  ): Promise<string> {
    const commitData = {
      type: 'asset_commit',
      settlementId: request.settlementId,
      assetDetails: request.assetDetails,
      timestamp: new Date().toISOString(),
    };

    const commitString = JSON.stringify(commitData);
    return createHash('sha3-256').update(commitString).digest('hex');
  }

  /**
   * Create temporal state commit
   */
  private async createTemporalStateCommit(
    request: GasCommitmentRequest
  ): Promise<string> {
    const commitData = {
      type: 'temporal_state',
      settlementId: request.settlementId,
      temporalState: request.temporalState,
      timestamp: new Date().toISOString(),
    };

    const commitString = JSON.stringify(commitData);
    return createHash('sha3-256').update(commitString).digest('hex');
  }

  /**
   * Hash all commitments
   */
  private hashCommitments(commitments: GasCommitment): string {
    const commitmentString = JSON.stringify({
      scbCommit: commitments.scbCommit,
      dbisCommit: commitments.dbisCommit,
      fxCommit: commitments.fxCommit || '',
      assetCommit: commitments.assetCommit || '',
      temporalState: commitments.temporalState || '',
    });

    return createHash('sha3-256').update(commitmentString).digest('hex');
  }

  /**
   * Verify all commits match
   */
  async verifyAllCommitsMatch(
    settlementId: string
  ): Promise<{ verified: boolean; missingCommits: string[] }> {
    const commitment = await prisma.gas_commitments.findFirst({
      where: { settlementId },
    });

    if (!commitment) {
      return { verified: false, missingCommits: ['commitment_not_found'] };
    }

    const missingCommits: string[] = [];

    if (!commitment.scbCommit) missingCommits.push('scb_commit');
    if (!commitment.dbisCommit) missingCommits.push('dbis_commit');

    // Optional commits
    // FX and asset commits are optional depending on transaction type

    const verified = missingCommits.length === 0;

    if (verified) {
      await prisma.gas_commitments.update({
        where: { id: commitment.id },
        data: { status: 'verified', verifiedAt: new Date() },
      });
    }

    return { verified, missingCommits };
  }

  /**
   * Get commitment by settlement ID
   */
  async getCommitment(settlementId: string) {
    return await prisma.gas_commitments.findFirst({
      where: { settlementId },
    });
  }
}

export const gasCommitmentService = new GasCommitmentService();

