// IBIN Coupon Service
// Cross-border CBDC coupon payments

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

export interface CouponPaymentRequest {
  bondId: string;
  paymentDate: Date;
  nodeId: string;
}

export interface CouponPaymentResult {
  paymentId: string;
  couponAmount: string;
  status: string;
  sovereignLedgerHash?: string;
  dbisLedgerHash?: string;
}

export class IbinCouponService {
  /**
   * Calculate coupon payment amount
   */
  async calculateCouponAmount(bondId: string): Promise<Decimal> {
    const bond = await prisma.digital_bonds.findUnique({
      where: { bondId },
    });

    if (!bond) {
      throw new Error(`Bond not found: ${bondId}`);
    }

    // Coupon amount = principal * coupon_rate / payment_frequency
    // Assuming annual payments for simplicity
    const couponAmount = bond.principal.mul(bond.couponRate).div(100);

    return couponAmount;
  }

  /**
   * Process coupon payment
   */
  async processCouponPayment(
    request: CouponPaymentRequest
  ): Promise<CouponPaymentResult> {
    const bond = await prisma.digital_bonds.findUnique({
      where: { bondId: request.bondId },
    });

    if (!bond) {
      throw new Error(`Bond not found: ${request.bondId}`);
    }

    if (bond.status !== 'active') {
      throw new Error(`Bond is not active: ${bond.status}`);
    }

    // Calculate coupon amount
    const couponAmount = await this.calculateCouponAmount(request.bondId);

    // Get bond holder (simplified - in production would track ownership)
    // For now, assume issuer pays to a default holder
    const issuerBankId = bond.issuerBankId;
    const holderBankId = bond.issuerBankId; // In production, get from ownership records

    // Post to GSS Master Ledger for dual-ledger settlement
    const ledgerResult = await gssMasterLedgerService.postToMasterLedger({
      nodeId: request.nodeId,
      sourceBankId: issuerBankId,
      destinationBankId: holderBankId,
      amount: couponAmount.toString(),
      currencyCode: bond.currencyCode,
      assetType: bond.settlementMode === 'cbdc' ? 'cbdc' : 'fiat',
    });

    // Create coupon payment record
    const paymentId = `COUPON-${uuidv4()}`;
    const payment = await prisma.bond_coupon_payments.create({
      data: {
        paymentId,
        bondId: request.bondId,
        couponAmount,
        currencyCode: bond.currencyCode,
        paymentDate: request.paymentDate,
        settlementMode: bond.settlementMode,
        sovereignLedgerHash: ledgerResult.sovereignLedgerHash,
        dbisLedgerHash: ledgerResult.dbisLedgerHash,
        dualLedgerCommit: ledgerResult.dualCommit,
        status: 'settled',
        settledAt: new Date(),
      },
    });

    return {
      paymentId: payment.paymentId,
      couponAmount: payment.couponAmount.toString(),
      status: payment.status,
      sovereignLedgerHash: payment.sovereignLedgerHash || undefined,
      dbisLedgerHash: payment.dbisLedgerHash || undefined,
    };
  }

  /**
   * Schedule coupon payments
   */
  async scheduleCouponPayments(bondId: string): Promise<void> {
    const bond = await prisma.digital_bonds.findUnique({
      where: { bondId },
    });

    if (!bond) {
      throw new Error(`Bond not found: ${bondId}`);
    }

    // Calculate payment dates (annual payments until maturity)
    const paymentDates: Date[] = [];
    const issueDate = bond.issuedAt;
    const maturityDate = bond.maturityDate;

    let currentDate = new Date(issueDate);
    currentDate.setFullYear(currentDate.getFullYear() + 1); // First payment after 1 year

    while (currentDate <= maturityDate) {
      paymentDates.push(new Date(currentDate));
      currentDate.setFullYear(currentDate.getFullYear() + 1);
    }

    // In production, would create scheduled payment jobs
    // For now, just log the schedule
    logger.info('Scheduled coupon payments', {
      bondId,
      paymentCount: paymentDates.length,
    });
  }

  /**
   * Get coupon payment history
   */
  async getCouponPaymentHistory(bondId: string): Promise<any[]> {
    const payments = await prisma.bond_coupon_payments.findMany({
      where: { bondId },
      orderBy: { paymentDate: 'desc' },
    });

    return payments;
  }
}

export const ibinCouponService = new IbinCouponService();

