// DSDM PMO Service
// Public Market Operations automation

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { dsdmLadderService } from './dsdm-ladder.service';


export interface PMORequest {
  sovereignBankId: string;
  operationType: string; // maturity_ladder, rollover, debt_refinancing
  operationConfig: Record<string, unknown>;
}

export class DsdmPmoService {
  /**
   * Execute Public Market Operation
   */
  async executePMO(request: PMORequest): Promise<{ pmoId: string }> {
    const pmoId = `PMO-${uuidv4()}`;

    let result: any;

    switch (request.operationType) {
      case 'maturity_ladder':
        result = await this.executeMaturityLadder(
          request.sovereignBankId,
          request.operationConfig
        );
        break;

      case 'rollover':
        result = await this.executeRolloverOperation(
          request.sovereignBankId,
          request.operationConfig
        );
        break;

      case 'debt_refinancing':
        result = await this.executeDebtRefinancing(
          request.sovereignBankId,
          request.operationConfig
        );
        break;

      default:
        throw new Error(`Unknown PMO operation type: ${request.operationType}`);
    }

    // Create PMO record
    const pmo = await prisma.publicMarketOperation.create({
      data: {
        pmoId,
        sovereignBankId: request.sovereignBankId,
        operationType: request.operationType,
        operationData: {
          config: request.operationConfig,
          result,
        },
        status: 'executed',
        executedAt: new Date(),
      },
    });

    return {
      pmoId: pmo.pmoId,
    };
  }

  /**
   * Execute maturity ladder operation
   */
  private async executeMaturityLadder(
    sovereignBankId: string,
    config: Record<string, unknown>
  ): Promise<any> {
    // Get upcoming maturities
    const daysAhead = (config.daysAhead as number) || 90;
    const maturities = await dsdmLadderService.getUpcomingMaturities(
      sovereignBankId,
      daysAhead
    );

    return {
      maturities,
      totalAmount: maturities.reduce(
        (sum, m) => sum.plus(m.principalAmount),
        new Decimal(0)
      ).toString(),
    };
  }

  /**
   * Execute rollover operation
   */
  private async executeRolloverOperation(
    sovereignBankId: string,
    config: Record<string, unknown>
  ): Promise<any> {
    const originalLadderId = config.originalLadderId as string;
    const rolloverAmount = config.rolloverAmount as string;
    const currencyCode = config.currencyCode as string;
    const newMaturityDate = new Date(config.newMaturityDate as string);
    const fundingSource = (config.fundingSource as string) || 'cbdc';

    const rollover = await dsdmLadderService.executeRollover({
      sovereignBankId,
      originalLadderId,
      rolloverAmount,
      currencyCode,
      newMaturityDate,
      fundingSource,
    });

    return rollover;
  }

  /**
   * Execute debt refinancing
   */
  private async executeDebtRefinancing(
    sovereignBankId: string,
    config: Record<string, unknown>
  ): Promise<any> {
    // Get maturing debt
    const daysAhead = (config.daysAhead as number) || 90;
    const maturities = await dsdmLadderService.getUpcomingMaturities(
      sovereignBankId,
      daysAhead
    );

    // Refinance each maturity
    const refinancings = [];

    for (const maturity of maturities) {
      const newMaturityDate = new Date(maturity.maturityDate);
      newMaturityDate.setFullYear(newMaturityDate.getFullYear() + 1); // Extend by 1 year

      const rollover = await dsdmLadderService.executeRollover({
        sovereignBankId,
        originalLadderId: maturity.ladderId,
        rolloverAmount: maturity.principalAmount.toString(),
        currencyCode: maturity.currencyCode,
        newMaturityDate,
        fundingSource: 'cbdc',
      });

      refinancings.push(rollover);
    }

    return {
      refinancings,
      count: refinancings.length,
    };
  }

  /**
   * Get PMO history
   */
  async getPMOHistory(sovereignBankId: string): Promise<any[]> {
    const pmos = await prisma.publicMarketOperation.findMany({
      where: { sovereignBankId },
      orderBy: { executedAt: 'desc' },
    });

    return pmos;
  }
}

export const dsdmPmoService = new DsdmPmoService();

