// Supervisory Dashboard Service
import { Prisma } from '@prisma/client';
// Real-time SRI, liquidity stress, CBDC penetration reports

import { v4 as uuidv4 } from 'uuid';
import { sriMonitorService } from '@/core/risk/sri/sri-monitor.service';
import { treasuryService } from '@/core/treasury/treasury.service';
import prisma from '@/shared/database/prisma';
import { logger } from '@/infrastructure/monitoring/logger';

export interface DashboardMetrics {
  sri?: {
    currentSRI: number;
    rating: string;
    trend: string;
  };
  liquidityStress?: {
    lcr: number;
    nsfr: number;
    stressLevel: string;
  };
  cbdcPenetration?: {
    totalCBDC: number;
    penetrationRate: number;
    growthRate: number;
  };
  incidentAlerts?: Array<{
    type: string;
    severity: string;
    description: string;
    timestamp: Date;
  }>;
}

export class DashboardService {
  /**
   * Get real-time SRI dashboard
   */
  async getSRIDashboard(sovereignBankId?: string): Promise<DashboardMetrics> {
    if (sovereignBankId) {
      const monitorResult = await sriMonitorService.monitorSRI(sovereignBankId);
      const history = await sriMonitorService.getSRIHistory(sovereignBankId, 7);

      const trend = history.length >= 2
        ? history[0].sriScore > history[1].sriScore
          ? 'increasing'
          : 'decreasing'
        : 'stable';

      return {
        sri: {
          currentSRI: monitorResult.currentSRI,
          rating: monitorResult.rating,
          trend,
        },
      };
    }

    // Aggregate for all banks
    const allBanks = await sriMonitorService.monitorAllBanks();
    const avgSRI = allBanks.reduce((sum: number, b: { sri?: number }) => sum + (b.sri ?? 0), 0) / allBanks.length;

    return {
      sri: {
        currentSRI: avgSRI,
        rating: this.getSRIRating(avgSRI),
        trend: 'aggregate',
      },
    };
  }

  /**
   * Get liquidity stress dashboard
   */
  async getLiquidityStressDashboard(sovereignBankId?: string): Promise<DashboardMetrics> {
    if (sovereignBankId) {
      const lcr = await treasuryService.calculateLCR(sovereignBankId);
      const nsfr = await treasuryService.calculateNSFR(sovereignBankId);

      const lcrValue = parseFloat(lcr);
      const nsfrValue = parseFloat(nsfr);

      let stressLevel = 'low';
      if (lcrValue < 1.0 || nsfrValue < 1.0) {
        stressLevel = 'high';
      } else if (lcrValue < 1.1 || nsfrValue < 1.1) {
        stressLevel = 'medium';
      }

      return {
        liquidityStress: {
          lcr: lcrValue,
          nsfr: nsfrValue,
          stressLevel,
        },
      };
    }

    // Aggregate for all banks
    const banks = await prisma.sovereign_banks.findMany({
      where: { status: 'active' },
    });

    const lcrValues: number[] = [];
    const nsfrValues: number[] = [];

    for (const bank of banks) {
      try {
        const lcr = await treasuryService.calculateLCR(bank.id);
        const nsfr = await treasuryService.calculateNSFR(bank.id);
        lcrValues.push(parseFloat(lcr));
        nsfrValues.push(parseFloat(nsfr));
      } catch (error) {
        logger.error('Error calculating liquidity for bank', {
          bankId: bank.id,
          error: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }

    const avgLCR = lcrValues.length > 0 ? lcrValues.reduce((a: number, b: number) => a + b, 0) / lcrValues.length : 0;
    const avgNSFR = nsfrValues.length > 0 ? nsfrValues.reduce((a: number, b: number) => a + b, 0) / nsfrValues.length : 0;

    return {
      liquidityStress: {
        lcr: avgLCR,
        nsfr: avgNSFR,
        stressLevel: 'aggregate',
      },
    };
  }

  /**
   * Get CBDC penetration dashboard
   */
  async getCBDCPenetrationDashboard(sovereignBankId?: string): Promise<DashboardMetrics> {
    const where: { sovereignBankId?: string } = {};
    if (sovereignBankId) {
      where.sovereignBankId = sovereignBankId;
    }

    const issuances = await prisma.cbdc_issuance.findMany({
      where,
      orderBy: { timestampUtc: 'desc' },
    });

    const totalCBDC = issuances.reduce(
      (sum: number, i: { netChange?: unknown }) => sum + parseFloat(String(i.netChange ?? 0)),
      0
    );

    // Get total fiat for penetration calculation
    const accounts = await prisma.bank_accounts.findMany({
      where: {
        ...where,
        assetType: {
          in: ['fiat', 'cbdc'],
        },
      },
    });

    const totalFiat = accounts
      .filter((a) => a.assetType === 'fiat')
      .reduce((sum: number, a: { balance?: { toString: () => string } }) => sum + parseFloat(a.balance?.toString() ?? '0'), 0);

    const totalAssets = totalFiat + totalCBDC;
    const penetrationRate = totalAssets > 0 ? (totalCBDC / totalAssets) * 100 : 0;

    // Calculate growth rate (last 30 days)
    const thirtyDaysAgo = new Date();
    thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

    const recentIssuances = issuances.filter((i) => i.timestampUtc >= thirtyDaysAgo);
    const recentCBDC = recentIssuances.reduce(
      (sum, i) => sum + parseFloat(i.netChange.toString()),
      0
    );

    const growthRate = totalCBDC > 0 ? (recentCBDC / totalCBDC) * 100 : 0;

    return {
      cbdcPenetration: {
        totalCBDC,
        penetrationRate,
        growthRate,
      },
    };
  }

  /**
   * Get incident alerts dashboard
   */
  async getIncidentAlertsDashboard(sovereignBankId?: string): Promise<DashboardMetrics> {
    const alerts: Array<{
      type: string;
      severity: string;
      description: string;
      timestamp: Date;
    }> = [];

    // Get SRI enforcements
    const where: { sovereignBankId?: string; status: string } = { status: 'active' };
    if (sovereignBankId) {
      where.sovereignBankId = sovereignBankId;
    }

    const enforcements = await prisma.sri_enforcements.findMany({
      where,
      include: { sovereign_risk_indices: true },
      orderBy: { createdAt: 'desc' },
      take: 10,
    });

    for (const enforcement of enforcements) {
      alerts.push({
        type: 'sri_enforcement',
        severity: enforcement.triggerLevel === 'sri_60' ? 'critical' : 'high',
        description: enforcement.action,
        timestamp: enforcement.createdAt,
      });
    }

    // Get default events
    const defaultEvents = await prisma.default_events.findMany({
      where: {
        ...(sovereignBankId ? { sovereignBankId } : {}),
        status: 'active',
      },
      orderBy: { createdAt: 'desc' },
      take: 10,
    });

    for (const event of defaultEvents) {
      alerts.push({
        type: 'default_event',
        severity: event.severity,
        description: event.description,
        timestamp: event.createdAt,
      });
    }

    return {
      incidentAlerts: alerts.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()),
    };
  }

  /**
   * Get comprehensive dashboard
   */
  async getComprehensiveDashboard(sovereignBankId?: string): Promise<DashboardMetrics> {
    const [sri, liquidity, cbdc, incidents] = await Promise.all([
      this.getSRIDashboard(sovereignBankId),
      this.getLiquidityStressDashboard(sovereignBankId),
      this.getCBDCPenetrationDashboard(sovereignBankId),
      this.getIncidentAlertsDashboard(sovereignBankId),
    ]);

    return {
      ...sri,
      ...liquidity,
      ...cbdc,
      ...incidents,
    };
  }

  /**
   * Update dashboard
   */
  async updateDashboard(
    dashboardType: string,
    sovereignBankId: string | null,
    metrics: Prisma.InputJsonValue
  ) {
    const dashboard = await prisma.supervisory_dashboards.findFirst({
      where: {
        dashboardType,
        sovereignBankId: sovereignBankId || null,
      },
    });

    if (dashboard) {
      return await prisma.supervisory_dashboards.update({
        where: { id: dashboard.id },
        data: {
          metrics,
          lastUpdated: new Date(),
        },
      });
    }

    return await prisma.supervisory_dashboards.create({
      data: {
        id: uuidv4(),
        dashboardId: uuidv4(),
        sovereignBankId: sovereignBankId || null,
        dashboardType,
        metrics,
        lastUpdated: new Date(),
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });
  }

  private getSRIRating(score: number): string {
    if (score <= 10) return 'AAA';
    if (score <= 20) return 'AA';
    if (score <= 30) return 'A';
    if (score <= 40) return 'BBB';
    if (score <= 50) return 'BB';
    if (score <= 60) return 'B';
    return 'CCC';
  }
}

export const dashboardService = new DashboardService();

