// Standardized Ledger Posting API
// Provides a standardized contract for all services to post ledger entries
//
// UPDATED: Uses ledgerPostingModule for atomic correctness

import { Decimal } from '@prisma/client/runtime/library';
import { ledgerPostingModule } from './ledger-posting.module';
import { DbisError, ErrorCode } from '@/shared/types';
import { logger } from '@/infrastructure/monitoring/logger';

export interface LedgerPostingRequest {
  referenceId: string;
  entries: Array<{
    debitAccountId: string;
    creditAccountId: string;
    amount: string; // Decimal as string
    currencyCode: string;
    assetType: 'fiat' | 'cbdc' | 'commodity' | 'security';
    description?: string;
  }>;
  transactionType: string;
  metadata?: Record<string, unknown>;
  fxRates?: Record<string, string>; // Currency pair -> rate
}

export interface LedgerPostingResponse {
  postingId: string;
  entryIds: string[];
  status: 'posted' | 'pending';
  timestamp: Date;
}

/**
 * Standardized posting API for all capability services
 * All money movement must go through this API
 */
export class LedgerPostingAPI {
  /**
   * Post ledger entries (standardized API)
   */
  async postEntries(request: LedgerPostingRequest): Promise<LedgerPostingResponse> {
    // Validate double-entry balance
    const totalDebits = request.entries.reduce((sum, entry) => {
      return sum.plus(new Decimal(entry.amount));
    }, new Decimal(0));

    const totalCredits = request.entries.reduce((sum, entry) => {
      return sum.plus(new Decimal(entry.amount));
    }, new Decimal(0));

    if (!totalDebits.equals(totalCredits)) {
      throw new DbisError(
        ErrorCode.VALIDATION_ERROR,
        `Double-entry validation failed: debits (${totalDebits}) != credits (${totalCredits})`
      );
    }

    // Post entries
    const entryIds: string[] = [];
    const ledgerId = 'MASTER'; // Default ledger

    for (const entry of request.entries) {
      try {
        // Use ledgerPostingModule for atomic correctness
        const result = await ledgerPostingModule.postEntry({
          ledgerId,
          debitAccountId: entry.debitAccountId,
          creditAccountId: entry.creditAccountId,
          amount: entry.amount,
          currencyCode: entry.currencyCode,
          assetType: entry.assetType,
          transactionType: request.transactionType,
          referenceId: `${request.referenceId}-${entryIds.length}`, // Unique ref per entry
          fxRate: request.fxRates?.[entry.currencyCode],
          metadata: {
            ...request.metadata,
            description: entry.description,
          },
        });

        entryIds.push(result.entryId);
      } catch (error) {
        logger.error(`Failed to post ledger entry`, {
          entry,
          error: error instanceof Error ? error.message : 'Unknown error',
        });
        throw error;
      }
    }

    logger.info(`Ledger entries posted`, {
      referenceId: request.referenceId,
      entryCount: entryIds.length,
    });

    return {
      postingId: request.referenceId,
      entryIds,
      status: 'posted',
      timestamp: new Date(),
    };
  }
}

export const ledgerPostingAPI = new LedgerPostingAPI();
