// SNFN Loan Service
// Loan eligibility: SRI_factor + reserve_strength + FX_exposure + liquidity_shortfall

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { sriCalculatorService } from '@/core/risk/sri/sri-calculator.service';


export interface CreateLoanRequest {
  nodeId: string;
  borrowerBankId: string;
  loanAmount: string;
  currencyCode: string;
  interestRate?: string;
  maturityDate?: Date;
}

export interface LoanResult {
  loanId: string;
  loanEligibility: string;
  status: string;
}

export class SnfnLoanService {
  /**
   * Calculate loan eligibility
   * Formula: SRI_factor + reserve_strength + FX_exposure + liquidity_shortfall
   */
  async calculateLoanEligibility(borrowerBankId: string): Promise<Decimal> {
    // Get SRI factor
    const sri = await sriCalculatorService.calculateSRI(borrowerBankId);
    const sriFactor = new Decimal(sri.sriScore.toString()).dividedBy(100); // Normalize to 0-1

    // Get reserve strength (simplified - would use actual reserve data)
    const reserveStrength = await this.getReserveStrength(borrowerBankId);

    // Get FX exposure (simplified - would use actual FX data)
    const fxExposure = await this.getFXExposure(borrowerBankId);

    // Get liquidity shortfall (simplified - would use actual liquidity data)
    const liquidityShortfall = await this.getLiquidityShortfall(borrowerBankId);

    // Calculate loan eligibility
    const loanEligibility = sriFactor
      .plus(reserveStrength)
      .plus(fxExposure)
      .plus(liquidityShortfall);

    return loanEligibility;
  }

  /**
   * Create loan request
   */
  async createLoan(request: CreateLoanRequest): Promise<LoanResult> {
    // Calculate loan eligibility
    const loanEligibility = await this.calculateLoanEligibility(request.borrowerBankId);

    // Get SRI and other factors for storage
    const sri = await sriCalculatorService.calculateSRI(request.borrowerBankId);
    const sriFactor = new Decimal(sri.sriScore.toString()).dividedBy(100);
    const reserveStrength = await this.getReserveStrength(request.borrowerBankId);
    const fxExposure = await this.getFXExposure(request.borrowerBankId);
    const liquidityShortfall = await this.getLiquidityShortfall(request.borrowerBankId);

    const loanId = `SNFN-LOAN-${uuidv4()}`;

    const loan = await prisma.supra_fund_loans.create({
      data: {
        loanId,
        nodeId: request.nodeId,
        borrowerBankId: request.borrowerBankId,
        loanAmount: new Decimal(request.loanAmount),
        currencyCode: request.currencyCode,
        sriFactor,
        reserveStrength,
        fxExposure,
        liquidityShortfall,
        loanEligibility,
        interestRate: request.interestRate ? new Decimal(request.interestRate) : null,
        maturityDate: request.maturityDate || null,
        status: 'pending',
      },
    });

    // Auto-approve if eligibility is high enough (threshold = 2.0)
    if (loanEligibility.gte(2.0)) {
      await prisma.supra_fund_loans.update({
        where: { loanId },
        data: {
          status: 'approved',
          approvedAt: new Date(),
        },
      });
    }

    return {
      loanId: loan.loanId,
      loanEligibility: loan.loanEligibility.toString(),
      status: loan.status,
    };
  }

  /**
   * Get reserve strength (simplified)
   */
  private async getReserveStrength(bankId: string): Promise<Decimal> {
    // In production, this would fetch actual reserve data
    // For now, return a simulated value
    return new Decimal(0.5 + Math.random() * 0.3); // 0.5 to 0.8
  }

  /**
   * Get FX exposure (simplified)
   */
  private async getFXExposure(bankId: string): Promise<Decimal> {
    // In production, this would calculate actual FX exposure
    // For now, return a simulated value
    return new Decimal(0.2 + Math.random() * 0.2); // 0.2 to 0.4
  }

  /**
   * Get liquidity shortfall (simplified)
   */
  private async getLiquidityShortfall(bankId: string): Promise<Decimal> {
    // In production, this would calculate actual liquidity shortfall
    // For now, return a simulated value
    return new Decimal(0.1 + Math.random() * 0.2); // 0.1 to 0.3
  }

  /**
   * Get loan
   */
  async getLoan(loanId: string) {
    return await prisma.supra_fund_loans.findUnique({
      where: { loanId },
      include: {
        node: true,
      },
    });
  }

  /**
   * List loans
   */
  async listLoans(nodeId?: string, borrowerBankId?: string) {
    return await prisma.supra_fund_loans.findMany({
      where: {
        ...(nodeId ? { nodeId } : {}),
        ...(borrowerBankId ? { borrowerBankId } : {}),
      },
      orderBy: { createdAt: 'desc' },
    });
  }
}

export const snfnLoanService = new SnfnLoanService();

