// AS4 Posting Engine Service
// Atomic debit/credit posting

import { v4 as uuidv4 } from 'uuid';
import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { gssMasterLedgerService } from '../gss/gss-master-ledger.service';
import { logger } from '@/infrastructure/monitoring/logger';

export interface PostingResult {
  postingId: string;
  status: 'POSTED' | 'FAILED';
  dbisLedgerHash?: string;
  error?: string;
}

export class PostingEngineService {
  /**
   * Post settlement instruction (atomic debit/credit)
   */
  async postInstruction(data: {
    instructionId: string;
    fromMemberId: string;
    toMemberId: string;
    debtorAccount: string;
    creditorAccount: string;
    amount: string;
    currency: string;
    valueDate: Date;
  }): Promise<PostingResult> {
    const postingId = `POSTING-${uuidv4()}`;

    try {
      // Extract member IDs from accounts
      const debtorMemberId = data.debtorAccount.split(':')[1];
      const creditorMemberId = data.creditorAccount.split(':')[1];

      // Post to GSS master ledger (atomic)
      const ledgerResult = await gssMasterLedgerService.postToMasterLedger(
        {
          nodeId: 'AS4-SETTLEMENT',
          sourceBankId: debtorMemberId,
          destinationBankId: creditorMemberId,
          amount: data.amount,
          currencyCode: data.currency,
          assetType: 'SETTLEMENT',
        },
        postingId
      );

      // Update instruction with posting ID
      await prisma.as4SettlementInstruction.updateMany({
        where: {
          instructionId: data.instructionId,
          fromMemberId: data.fromMemberId,
        },
        data: {
          postingId,
          status: 'POSTED_FINAL',
          finalityStatus: 'FINAL',
          updatedAt: new Date(),
        },
      });

      logger.info('Settlement posted', {
        postingId,
        instructionId: data.instructionId,
        amount: data.amount,
        currency: data.currency,
        dbisLedgerHash: ledgerResult.dbisLedgerHash,
      });

      return {
        postingId,
        status: 'POSTED',
        dbisLedgerHash: ledgerResult.dbisLedgerHash,
      };
    } catch (error) {
      logger.error('Posting failed', {
        postingId,
        instructionId: data.instructionId,
        error: error instanceof Error ? error.message : 'Unknown error',
      });

      // Update instruction status
      await prisma.as4SettlementInstruction.updateMany({
        where: {
          instructionId: data.instructionId,
          fromMemberId: data.fromMemberId,
        },
        data: {
          status: 'REJECTED',
          rejectReason: error instanceof Error ? error.message : 'Posting failed',
          updatedAt: new Date(),
        },
      });

      return {
        postingId,
        status: 'FAILED',
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Get posting status
   */
  async getPostingStatus(postingId: string) {
    const instruction = await prisma.as4SettlementInstruction.findFirst({
      where: { postingId },
    });

    if (!instruction) {
      return null;
    }

    return {
      postingId,
      instructionId: instruction.instructionId,
      status: instruction.status,
      finalityStatus: instruction.finalityStatus,
      createdAt: instruction.createdAt,
    };
  }
}

export const postingEngineService = new PostingEngineService();
