// GRU Transparency & Disclosure Service
// Implements daily price fixings, liquidity reports, bond health metrics, stress tests, and Ω-Layer proofs

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';
import { gruIndexService } from './gru-index.service';
import { gruBondsService } from './gru-bonds.service';
import { gruStressTestService } from './gru-stress-test.service';


export type ReportType =
  | 'daily_price_fixing'
  | 'liquidity_report'
  | 'bond_health'
  | 'stress_test'
  | 'omega_proof';

export interface TransparencyReportRequest {
  reportType: ReportType;
  reportDate?: Date;
  includeDetails?: boolean;
}

export interface DailyPriceFixing {
  date: Date;
  gruTiers: {
    M00: { xauValue: Decimal; usdValue: Decimal };
    M0: { xauValue: Decimal; usdValue: Decimal };
    M1: { xauValue: Decimal; usdValue: Decimal };
  };
  indexes: {
    LiXAU: Decimal;
    LiPMG: Decimal;
    LiBMG1: Decimal;
    LiBMG2: Decimal;
    LiBMG3: Decimal;
  };
}

export interface LiquidityReport {
  date: Date;
  totalLiquidity: Decimal;
  tierBreakdown: {
    M00: Decimal;
    M0: Decimal;
    M1: Decimal;
  };
  activeIssuances: number;
  activeBonds: number;
  liquidityTrend: 'increasing' | 'stable' | 'decreasing';
}

export interface BondHealthMetrics {
  date: Date;
  totalBonds: number;
  activeBonds: number;
  totalPrincipal: Decimal;
  averageMaturity: number;
  defaultRate: Decimal;
  couponPaymentRate: Decimal;
  healthScore: number; // 0-100
}

export class GruTransparencyService {
  /**
   * Generate daily price fixing
   */
  async generateDailyPriceFixing(
    date?: Date
  ): Promise<{ reportId: string; data: DailyPriceFixing }> {
    const reportDate = date || new Date();
    logger.info('GRU Transparency: Generating daily price fixing', { reportDate });

    // Get all indexes
    const indexes = await gruIndexService.getAllIndexes();
    const indexMap: Record<string, Decimal> = {};
    for (const index of indexes) {
      indexMap[index.indexCode] = index.currentValue;
    }

    // Get XAU value (assuming LiXAU is XAU-based)
    const xauIndex = indexes.find((i) => i.indexCode === 'LiXAU');
    const xauValue = xauIndex?.currentValue || new Decimal(0);

    // Calculate GRU tier values
    // M00 = 100 * XAU, M0 = M00 / 5, M1 = M00 / 25 (from supplement A)
    const m00XauValue = xauValue.times(100);
    const m0XauValue = m00XauValue.dividedBy(5);
    const m1XauValue = m00XauValue.dividedBy(25);

    // Convert to USD (simplified - should use actual FX rates)
    const xauToUsdRate = new Decimal(2000); // Placeholder
    const m00UsdValue = m00XauValue.times(xauToUsdRate);
    const m0UsdValue = m0XauValue.times(xauToUsdRate);
    const m1UsdValue = m1XauValue.times(xauToUsdRate);

    const priceFixing: DailyPriceFixing = {
      date: reportDate,
      gruTiers: {
        M00: {
          xauValue: m00XauValue,
          usdValue: m00UsdValue,
        },
        M0: {
          xauValue: m0XauValue,
          usdValue: m0UsdValue,
        },
        M1: {
          xauValue: m1XauValue,
          usdValue: m1UsdValue,
        },
      },
      indexes: {
        LiXAU: indexMap['LiXAU'] || new Decimal(0),
        LiPMG: indexMap['LiPMG'] || new Decimal(0),
        LiBMG1: indexMap['LiBMG1'] || new Decimal(0),
        LiBMG2: indexMap['LiBMG2'] || new Decimal(0),
        LiBMG3: indexMap['LiBMG3'] || new Decimal(0),
      },
    };

    // Create transparency report
    const report = await prisma.gruTransparencyReport.create({
      data: {
        reportId: `GRU-TRANS-${uuidv4()}`,
        reportType: 'daily_price_fixing',
        reportDate: reportDate,
        reportData: priceFixing as any,
        status: 'generated',
      },
    });

    logger.info('GRU Transparency: Daily price fixing generated', {
      reportId: report.reportId,
    });

    return {
      reportId: report.reportId,
      data: priceFixing,
    };
  }

  /**
   * Generate liquidity report
   */
  async generateLiquidityReport(
    date?: Date
  ): Promise<{ reportId: string; data: LiquidityReport }> {
    const reportDate = date || new Date();
    logger.info('GRU Transparency: Generating liquidity report', { reportDate });

    // Get all GRU units
    const gruUnits = await prisma.gruUnit.findMany({
      where: { status: 'active' },
    });

    // Calculate tier breakdown
    let m00Total = new Decimal(0);
    let m0Total = new Decimal(0);
    let m1Total = new Decimal(0);

    for (const unit of gruUnits) {
      switch (unit.unitType) {
        case 'M00':
          m00Total = m00Total.plus(unit.amount);
          break;
        case 'M0':
          m0Total = m0Total.plus(unit.amount);
          break;
        case 'M1':
          m1Total = m1Total.plus(unit.amount);
          break;
      }
    }

    const totalLiquidity = m00Total.plus(m0Total).plus(m1Total);

    // Get active issuances
    const activeIssuances = await prisma.gruIssuance.count({
      where: {
        status: 'issued',
      },
    });

    // Get active bonds
    const activeBonds = await prisma.gruBond.count({
      where: {
        status: 'active',
      },
    });

    // Determine liquidity trend (simplified)
    const liquidityTrend: 'increasing' | 'stable' | 'decreasing' = 'stable';

    const liquidityReport: LiquidityReport = {
      date: reportDate,
      totalLiquidity,
      tierBreakdown: {
        M00: m00Total,
        M0: m0Total,
        M1: m1Total,
      },
      activeIssuances,
      activeBonds,
      liquidityTrend,
    };

    // Create transparency report
    const report = await prisma.gruTransparencyReport.create({
      data: {
        reportId: `GRU-TRANS-${uuidv4()}`,
        reportType: 'liquidity_report',
        reportDate: reportDate,
        reportData: liquidityReport as any,
        status: 'generated',
      },
    });

    logger.info('GRU Transparency: Liquidity report generated', {
      reportId: report.reportId,
    });

    return {
      reportId: report.reportId,
      data: liquidityReport,
    };
  }

  /**
   * Generate bond health metrics
   */
  async generateBondHealthMetrics(
    date?: Date
  ): Promise<{ reportId: string; data: BondHealthMetrics }> {
    const reportDate = date || new Date();
    logger.info('GRU Transparency: Generating bond health metrics', { reportDate });

    // Get all bonds
    const bonds = await prisma.gruBond.findMany({
      include: {
        coupons: true,
      },
    });

    const totalBonds = bonds.length;
    const activeBonds = bonds.filter((b) => b.status === 'active').length;

    // Calculate total principal
    let totalPrincipal = new Decimal(0);
    for (const bond of bonds) {
      totalPrincipal = totalPrincipal.plus(bond.principalAmount);
    }

    // Calculate average maturity
    const now = new Date();
    let totalMaturityDays = 0;
    for (const bond of bonds) {
      const maturityDays =
        (bond.maturityDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
      totalMaturityDays += maturityDays;
    }
    const averageMaturity = totalBonds > 0 ? totalMaturityDays / totalBonds : 0;

    // Calculate default rate
    const defaultedBonds = bonds.filter((b) => b.status === 'defaulted').length;
    const defaultRate =
      totalBonds > 0
        ? new Decimal(defaultedBonds).dividedBy(totalBonds).times(100)
        : new Decimal(0);

    // Calculate coupon payment rate
    let totalCoupons = 0;
    let paidCoupons = 0;
    for (const bond of bonds) {
      totalCoupons += bond.coupons.length;
      paidCoupons += bond.coupons.filter((c) => c.status === 'paid').length;
    }
    const couponPaymentRate =
      totalCoupons > 0
        ? new Decimal(paidCoupons).dividedBy(totalCoupons).times(100)
        : new Decimal(100);

    // Calculate health score (0-100)
    const healthScore = this.calculateBondHealthScore(
      defaultRate,
      couponPaymentRate,
      activeBonds,
      totalBonds
    );

    const bondHealth: BondHealthMetrics = {
      date: reportDate,
      totalBonds,
      activeBonds,
      totalPrincipal,
      averageMaturity,
      defaultRate,
      couponPaymentRate,
      healthScore,
    };

    // Create transparency report
    const report = await prisma.gruTransparencyReport.create({
      data: {
        reportId: `GRU-TRANS-${uuidv4()}`,
        reportType: 'bond_health',
        reportDate: reportDate,
        reportData: bondHealth as any,
        status: 'generated',
      },
    });

    logger.info('GRU Transparency: Bond health metrics generated', {
      reportId: report.reportId,
    });

    return {
      reportId: report.reportId,
      data: bondHealth,
    };
  }

  /**
   * Get stress test results
   */
  async getStressTestResults(limit: number = 10): Promise<any[]> {
    const tests = await prisma.gruStressTest.findMany({
      where: {
        status: 'completed',
      },
      include: {
        results: true,
      },
      orderBy: {
        completedAt: 'desc',
      },
      take: limit,
    });

    return tests.map((test) => ({
      testId: test.testId,
      testName: test.testName,
      stressRegime: test.stressRegime,
      testType: test.testType,
      completedAt: test.completedAt,
      results: test.results,
    }));
  }

  /**
   * Get Ω-Layer settlement proofs
   */
  async getOmegaLayerProofs(limit: number = 100): Promise<any[]> {
    const finalities = await prisma.gruOmegaLayerFinality.findMany({
      where: {
        status: 'finalized',
      },
      include: {
        pipeline: true,
      },
      orderBy: {
        finalizedAt: 'desc',
      },
      take: limit,
    });

    return finalities.map((finality) => ({
      finalityId: finality.finalityId,
      pipelineId: finality.pipelineId,
      mergeOperationId: finality.mergeOperationId,
      finalityProof: finality.finalityProof,
      causalityStable: finality.causalityStable,
      multiRealityReconciled: finality.multiRealityReconciled,
      finalizedAt: finality.finalizedAt,
    }));
  }

  /**
   * Get transparency report by type and date
   */
  async getTransparencyReport(
    reportType: ReportType,
    reportDate?: Date
  ): Promise<any> {
    const where: any = { reportType };
    if (reportDate) {
      where.reportDate = reportDate;
    }

    return await prisma.gruTransparencyReport.findFirst({
      where,
      orderBy: {
        reportDate: 'desc',
      },
    });
  }

  /**
   * Publish transparency report
   */
  async publishReport(reportId: string): Promise<void> {
    await prisma.gruTransparencyReport.update({
      where: { reportId },
      data: {
        status: 'published',
        publishedAt: new Date(),
      },
    });

    logger.info('GRU Transparency: Report published', { reportId });
  }

  /**
   * Calculate bond health score
   */
  private calculateBondHealthScore(
    defaultRate: Decimal,
    couponPaymentRate: Decimal,
    activeBonds: number,
    totalBonds: number
  ): number {
    // Health score formula:
    // Base score: 100
    // - Default rate penalty: -defaultRate * 2
    // - Coupon payment bonus: +couponPaymentRate * 0.1
    // - Active bonds ratio: + (activeBonds / totalBonds) * 20

    const defaultPenalty = defaultRate.toNumber() * 2;
    const couponBonus = couponPaymentRate.toNumber() * 0.1;
    const activeRatio = totalBonds > 0 ? (activeBonds / totalBonds) * 20 : 0;

    let score = 100 - defaultPenalty + couponBonus + activeRatio;

    // Clamp to 0-100
    score = Math.max(0, Math.min(100, score));

    return Math.round(score);
  }
}

export const gruTransparencyService = new GruTransparencyService();

