// AS4 Reconciliation & Reporting Service
// Statements, audit exports

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { logger } from '@/infrastructure/monitoring/logger';

export interface StatementEntry {
  instructionId: string;
  postingId: string;
  valueDate: Date;
  currency: string;
  amount: string;
  debtorAccount?: string;
  creditorAccount?: string;
  balanceAfter?: string;
  finalityStatus: string;
}

export interface Statement {
  memberId: string;
  accountId: string;
  currency: string;
  startDate: Date;
  endDate: Date;
  openingBalance: string;
  closingBalance: string;
  entries: StatementEntry[];
}

export class ReconciliationService {
  /**
   * Generate statement for member account
   */
  async generateStatement(
    memberId: string,
    accountId: string,
    startDate: Date,
    endDate: Date
  ): Promise<Statement> {
    // Extract currency from account
    const accountParts = accountId.split(':');
    const currency = accountParts[2] || 'USD';

    // Get all instructions for this account (as debtor or creditor)
    const instructions = await prisma.as4SettlementInstruction.findMany({
      where: {
        OR: [
          { debtorAccount: accountId },
          { creditorAccount: accountId },
        ],
        valueDate: {
          gte: startDate,
          lte: endDate,
        },
        status: 'POSTED_FINAL',
      },
      include: {
        advices: true,
      },
      orderBy: {
        valueDate: 'asc',
      },
    });

    // Build statement entries
    const entries: StatementEntry[] = [];
    let runningBalance = new Decimal('0'); // TODO: Get opening balance from ledger

    for (const instruction of instructions) {
      const advice = instruction.advices.find(
        (a) =>
          (a.creditedAccount === accountId && a.adviceType === 'DBIS.AD.910') ||
          (a.debitedAccount === accountId && a.adviceType === 'DBIS.AD.900')
      );

      if (advice) {
        const amount = new Decimal(advice.amount.toString());
        if (advice.creditedAccount === accountId) {
          runningBalance = runningBalance.plus(amount);
        } else {
          runningBalance = runningBalance.minus(amount);
        }

        entries.push({
          instructionId: instruction.instructionId,
          postingId: advice.postingId,
          valueDate: instruction.valueDate,
          currency: instruction.currency,
          amount: advice.amount.toString(),
          debtorAccount: advice.debitedAccount || undefined,
          creditorAccount: advice.creditedAccount || undefined,
          balanceAfter: runningBalance.toString(),
          finalityStatus: advice.finalityStatus,
        });
      }
    }

    return {
      memberId,
      accountId,
      currency,
      startDate,
      endDate,
      openingBalance: '0.00', // TODO: Get from ledger
      closingBalance: runningBalance.toString(),
      entries,
    };
  }

  /**
   * Export audit trail
   */
  async exportAuditTrail(
    instructionId: string,
    fromMemberId: string
  ): Promise<any> {
    const instruction = await prisma.as4SettlementInstruction.findUnique({
      where: {
        fromMemberId_instructionId: {
          instructionId,
          fromMemberId,
        },
      },
      include: {
        advices: true,
        member: true,
      },
    });

    if (!instruction) {
      return null;
    }

    return {
      instruction: {
        instructionId: instruction.instructionId,
        messageId: instruction.messageId,
        fromMemberId: instruction.fromMemberId,
        toMemberId: instruction.toMemberId,
        businessType: instruction.businessType,
        valueDate: instruction.valueDate,
        currency: instruction.currency,
        amount: instruction.amount.toString(),
        status: instruction.status,
        postingId: instruction.postingId,
        finalityStatus: instruction.finalityStatus,
        payloadHash: instruction.payloadHash,
        signatureEvidence: instruction.signatureEvidence,
        as4ReceiptEvidence: instruction.as4ReceiptEvidence,
        compliancePackageRef: instruction.compliancePackageRef,
        createdAt: instruction.createdAt,
        updatedAt: instruction.updatedAt,
      },
      advices: instruction.advices.map((a) => ({
        adviceId: a.adviceId,
        adviceType: a.adviceType,
        postedAt: a.postedAt,
        postingId: a.postingId,
        currency: a.currency,
        amount: a.amount.toString(),
        finalityStatus: a.finalityStatus,
      })),
    };
  }
}

export const reconciliationService = new ReconciliationService();
