// Supranational Bonds Service
// GRB and CRB structures

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


export type SupranationalBondType = 'GRB' | 'CRB';
export type CommodityIndexType = 'XAU' | 'PGM' | 'BMG1' | 'BMG2' | 'BMG3';

export interface IssueSupranationalBondRequest {
  bondType: SupranationalBondType;
  bondName: string;
  principalAmount: string;
  supranationalCouncilId: string;
  reserveBacking: Record<string, any>;
  commodityIndex?: CommodityIndexType; // For CRB
  maturityYears: number;
  couponRate: string;
}

export interface ReserveVerificationRequest {
  bondId: string;
  verificationType: 'physical_audit' | 'certificate_verification' | 'custodian_verification';
  reserveAmount: string;
  reserveType: 'gru_reserve' | 'commodity_reserve';
  commodityType?: string;
  custodianId?: string;
  certificateHash?: string;
}

export class SupranationalBondsService {
  /**
   * Issue supranational bond
   */
  async issueBond(request: IssueSupranationalBondRequest): Promise<string> {
    logger.info('GRU: Issuing supranational bond', { request });

    const bondId = `${request.bondType}-${uuidv4()}`;
    const maturityDate = new Date();
    maturityDate.setFullYear(maturityDate.getFullYear() + request.maturityYears);

    const bond = await prisma.supranational_bonds.create({
      data: {
        bondId,
        bondType: request.bondType,
        bondName: request.bondName,
        principalAmount: new Decimal(request.principalAmount),
        supranationalCouncilId: request.supranationalCouncilId,
        reserveBacking: JSON.stringify(request.reserveBacking),
        commodityIndex: request.commodityIndex,
        maturityDate,
        couponRate: new Decimal(request.couponRate),
        status: 'active',
        issuedAt: new Date(),
      },
    });

    logger.info('GRU: Supranational bond issued', { bondId, bondType: request.bondType });

    return bondId;
  }

  /**
   * Pay bond coupon
   */
  async payCoupon(bondId: string): Promise<string> {
    const bond = await prisma.supranational_bonds.findUnique({
      where: { bondId },
    });

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

    const couponAmount = bond.principalAmount.times(bond.couponRate);
    const couponId = `COUPON-${uuidv4()}`;

    await prisma.supranational_bond_coupons.create({
      data: {
        couponId,
        bondId,
        couponAmount,
        paymentDate: new Date(),
        status: 'paid',
        paidAt: new Date(),
      },
    });

    logger.info('GRU: Supranational bond coupon paid', { bondId, couponAmount: couponAmount.toString() });

    return couponId;
  }

  /**
   * Verify reserve
   */
  async verifyReserve(request: ReserveVerificationRequest): Promise<string> {
    logger.info('GRU: Verifying reserve', { request });

    const bond = await prisma.supranational_bonds.findUnique({
      where: { bondId: request.bondId },
    });

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

    const verificationId = `VERIFY-${uuidv4()}`;
    const nextVerificationDate = new Date();
    nextVerificationDate.setMonth(nextVerificationDate.getMonth() + 6); // Next verification in 6 months

    const verification = await prisma.reserveVerification.create({
      data: {
        verificationId,
        bondId: request.bondId,
        verificationType: request.verificationType,
        reserveAmount: new Decimal(request.reserveAmount),
        reserveType: request.reserveType,
        commodityType: request.commodityType,
        custodianId: request.custodianId,
        certificateHash: request.certificateHash,
        verificationStatus: 'verified',
        verifiedAt: new Date(),
        nextVerificationDate,
      },
    });

    logger.info('GRU: Reserve verified', { verificationId });

    return verificationId;
  }

  /**
   * Get bond by ID
   */
  async getBond(bondId: string) {
    return await prisma.supranational_bonds.findUnique({
      where: { bondId },
      include: {
        coupons: {
          orderBy: { paymentDate: 'desc' },
        },
        reserveVerifications: {
          orderBy: { verifiedAt: 'desc' },
        },
      },
    });
  }

  /**
   * Get bonds by type
   */
  async getBondsByType(bondType: SupranationalBondType) {
    return await prisma.supranational_bonds.findMany({
      where: {
        bondType,
        status: 'active',
      },
      include: {
        coupons: true,
        reserveVerifications: {
          take: 1,
          orderBy: { verifiedAt: 'desc' },
        },
      },
    });
  }

  /**
   * Redeem bond
   */
  async redeemBond(bondId: string): Promise<void> {
    const bond = await prisma.supranational_bonds.findUnique({
      where: { bondId },
    });

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

    if (new Date() < bond.maturityDate) {
      throw new Error(`Bond not yet at maturity: ${bondId}`);
    }

    await prisma.supranational_bonds.update({
      where: { bondId },
      data: {
        status: 'redeemed',
        updatedAt: new Date(),
      },
    });

    logger.info('GRU: Supranational bond redeemed', { bondId });
  }
}

export const supranationalBondsService = new SupranationalBondsService();

