// BEIE Penalty Service
// Predictive penalty contract application
// Logic: if (SRP_risk > threshold) impose_liquidity_penalty()

import { Prisma } from '@prisma/client';
import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { beieMetricsService } from './beie-metrics.service';


export interface CreatePenaltyRequest {
  entityId: string;
  entityType: string; // retail_cbdc_user, institution, sovereign
  penaltyType: string; // liquidity_penalty, fee_increase, access_restriction
  penaltyAmount?: string;
  penaltyReason: string; // risky_behavior_detected, srp_risk_threshold_exceeded
  threshold?: string;
  predictiveContract?: Record<string, unknown>;
}

export interface PenaltyResult {
  penaltyId: string;
  status: string;
}

export class BeiePenaltyService {
  /**
   * Create behavioral penalty
   * Auto-applied when risky behavior detected
   */
  async createPenalty(request: CreatePenaltyRequest): Promise<PenaltyResult> {
    // Get SRP risk score
    const srpMetric = await beieMetricsService.getLatestMetric(
      request.entityId,
      'srp'
    );

    let riskScore = new Decimal(0);
    if (srpMetric) {
      riskScore = srpMetric.metricValue;
    } else {
      // Calculate SRP if not available
      const metric = await beieMetricsService.calculateMetric({
        entityId: request.entityId,
        entityType: request.entityType,
        metricType: 'srp',
      });
      riskScore = new Decimal(metric.metricValue);
    }

    // Use provided threshold or default
    const threshold = request.threshold
      ? new Decimal(request.threshold)
      : new Decimal(0.5);

    // Check if SRP_risk > threshold
    if (riskScore.gt(threshold)) {
      // Calculate penalty amount if not provided
      let penaltyAmount = new Decimal(0);
      if (request.penaltyAmount) {
        penaltyAmount = new Decimal(request.penaltyAmount);
      } else {
        penaltyAmount = await this.calculatePenaltyAmount(
          request.penaltyType,
          riskScore,
          threshold
        );
      }

      const penaltyId = `BEIE-PEN-${uuidv4()}`;

      const penalty = await prisma.behavioralPenalty.create({
        data: {
          penaltyId,
          entityId: request.entityId,
          entityType: request.entityType,
          penaltyType: request.penaltyType,
          penaltyAmount,
          penaltyReason: request.penaltyReason,
          riskScore,
          threshold,
          predictiveContract: request.predictiveContract ? (request.predictiveContract as Prisma.InputJsonValue) : Prisma.JsonNull,
          status: 'pending',
        },
      });

      // Auto-apply penalty
      await this.applyPenalty(penaltyId);

      return {
        penaltyId: penalty.penaltyId,
        status: penalty.status,
      };
    } else {
      throw new Error(
        `Risk score ${riskScore.toString()} does not exceed threshold ${threshold.toString()}`
      );
    }
  }

  /**
   * Calculate penalty amount
   */
  private async calculatePenaltyAmount(
    penaltyType: string,
    riskScore: Decimal,
    threshold: Decimal
  ): Promise<Decimal> {
    // Calculate excess risk
    const excessRisk = riskScore.minus(threshold);

    // Base penalty amounts
    const basePenalties: Record<string, number> = {
      liquidity_penalty: 1000,
      fee_increase: 100,
      access_restriction: 0, // No monetary amount
    };

    const basePenalty = basePenalties[penaltyType] || 100;

    // Scale by excess risk
    return new Decimal(basePenalty * parseFloat(excessRisk.toString()));
  }

  /**
   * Apply penalty
   * Logic: if (SRP_risk > threshold) impose_liquidity_penalty()
   */
  async applyPenalty(penaltyId: string): Promise<void> {
    const penalty = await prisma.behavioralPenalty.findUnique({
      where: { penaltyId },
    });

    if (!penalty || penalty.status !== 'pending') {
      return;
    }

    // In production, this would actually apply the penalty
    // (deduct funds, increase fees, restrict access, etc.)
    await prisma.behavioralPenalty.update({
      where: { penaltyId },
      data: {
        status: 'applied',
        appliedAt: new Date(),
      },
    });
  }

  /**
   * Check and auto-apply penalties based on SRP risk
   */
  async checkAndApplyPenalties(entityId: string, entityType: string): Promise<void> {
    const srpMetric = await beieMetricsService.getLatestMetric(entityId, 'srp');

    if (!srpMetric) {
      return;
    }

    const riskScore = srpMetric.metricValue;
    const threshold = new Decimal(0.5); // Default threshold

    if (riskScore.gt(threshold)) {
      // Auto-create and apply penalty
      await this.createPenalty({
        entityId,
        entityType,
        penaltyType: 'liquidity_penalty',
        penaltyReason: 'srp_risk_threshold_exceeded',
        threshold: threshold.toString(),
      });
    }
  }

  /**
   * Get penalty
   */
  async getPenalty(penaltyId: string) {
    return await prisma.behavioralPenalty.findUnique({
      where: { penaltyId },
    });
  }

  /**
   * List penalties for entity
   */
  async listPenalties(entityId: string, status?: string) {
    return await prisma.behavioralPenalty.findMany({
      where: {
        entityId,
        ...(status ? { status } : {}),
      },
      orderBy: { createdAt: 'desc' },
    });
  }
}

export const beiePenaltyService = new BeiePenaltyService();

