// GRU Supranational Issuance Service
// Volume II: Supranational Reserve Framework
// Extends GruIssuanceService with supranational issuance workflow

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 { gruIssuanceService, IssuanceClass } from './gru-issuance.service';
import { gruIndexService, GruIndexCode } from './gru-index.service';
import { gruReservePoolService } from './gru-reserve-pool.service';


export type ReserveClass = 'SR-1' | 'SR-2' | 'SR-3';

export interface SupranationalIssuanceRequest {
  sovereignBankId?: string;
  entityId: string;
  reserveClass: ReserveClass;
  issuanceClass: IssuanceClass;
  amount: string;
  unitType: 'M00' | 'M0' | 'M1';
  metalIndexLink: GruIndexCode;
  poolId?: string;
  registrarOfficeId: string;
}

export interface EligibilityCheckResult {
  eligible: boolean;
  smiaCompliance: boolean;
  ilieCompliance: boolean;
  reserveAdequacy: boolean;
  reasons?: string[];
}

export interface SupranationalIssuanceResult {
  issuanceId: string;
  reserveClass: string;
  amount: Decimal;
  status: string;
  eligibilityStatus: string;
  poolAllocationId?: string;
}

export class GruSupranationalIssuanceService {
  /**
   * Supranational issuance workflow:
   * Reserve Request → Eligibility Check → GRU Index Verification → Allocation → Registration → Settlement → Ω-Layer Finality
   */
  async issueSupranationalGru(
    request: SupranationalIssuanceRequest
  ): Promise<SupranationalIssuanceResult> {
    logger.info('GRU Supranational Issuance: Starting issuance', { request });

    // Step 1: Eligibility Check
    const eligibility = await this.checkEligibility(
      request.entityId,
      request.sovereignBankId,
      request.reserveClass
    );

    if (!eligibility.eligible) {
      throw new Error(
        `Entity not eligible for supranational issuance: ${eligibility.reasons?.join(', ')}`
      );
    }

    // Step 2: GRU Index Verification
    const index = await gruIndexService.getIndex(request.metalIndexLink);
    if (!index) {
      throw new Error(`GRU index not found: ${request.metalIndexLink}`);
    }

    // Step 3: Create standard GRU issuance
    const issuanceResult = await gruIssuanceService.issueGru({
      sovereignBankId: request.sovereignBankId || '',
      issuanceClass: request.issuanceClass,
      amount: request.amount,
      unitType: request.unitType,
      metalIndexLink: request.metalIndexLink,
      registrarOfficeId: request.registrarOfficeId,
    });

    // Step 4: Update issuance with supranational fields
    const issuance = await prisma.gruIssuance.update({
      where: { issuanceId: issuanceResult.issuanceId },
      data: {
        supranationalEntityId: request.entityId,
        reserveClass: request.reserveClass,
        eligibilityStatus: 'eligible',
        smiaCompliance: eligibility.smiaCompliance,
        ilieCompliance: eligibility.ilieCompliance,
      },
    });

    // Step 5: Allocate to reserve pool if poolId provided
    let poolAllocationId: string | undefined;
    if (request.poolId) {
      poolAllocationId = await gruReservePoolService.allocateReserves({
        poolId: request.poolId,
        reserveClassId: await this.getReserveClassId(request.reserveClass),
        amount: request.amount,
        entityId: request.entityId,
        sovereignBankId: request.sovereignBankId,
        allocationType: 'initial_allocation',
      });
    }

    logger.info('GRU Supranational Issuance: Issuance completed', {
      issuanceId: issuance.issuanceId,
      reserveClass: request.reserveClass,
      poolAllocationId,
    });

    return {
      issuanceId: issuance.issuanceId,
      reserveClass: request.reserveClass,
      amount: new Decimal(request.amount),
      status: issuance.status,
      eligibilityStatus: issuance.eligibilityStatus || 'eligible',
      poolAllocationId,
    };
  }

  /**
   * Check eligibility for supranational issuance
   * Criteria:
   * - Sovereign or supranational entity
   * - Demonstrated reserve adequacy
   * - Compliance with SMIA
   * - Accepts DBIS oversight
   * - Causality-stable sovereign identity per ILIE
   */
  async checkEligibility(
    entityId: string,
    sovereignBankId?: string,
    reserveClass?: ReserveClass
  ): Promise<EligibilityCheckResult> {
    logger.info('GRU Supranational Issuance: Checking eligibility', {
      entityId,
      sovereignBankId,
      reserveClass,
    });

    const reasons: string[] = [];
    let smiaCompliance = false;
    let ilieCompliance = false;
    let reserveAdequacy = false;

    // Check if entity exists
    const entity = await prisma.supranationalEntity.findUnique({
      where: { entityId },
    });

    if (!entity) {
      return {
        eligible: false,
        smiaCompliance: false,
        ilieCompliance: false,
        reserveAdequacy: false,
        reasons: ['Supranational entity not found'],
      };
    }

    // Check SMIA compliance (Sovereign Monetary Instruments Act)
    // In production, would check actual compliance records
    smiaCompliance = entity.status === 'active';
    if (!smiaCompliance) {
      reasons.push('Entity not in active status');
    }

    // Check ILIE compliance (causality-stable sovereign identity)
    // In production, would verify identity stability
    if (sovereignBankId) {
      const bank = await prisma.sovereignBank.findUnique({
        where: { id: sovereignBankId },
      });
      ilieCompliance = bank?.status === 'active' && !!bank.rootSovereignKey;
      if (!ilieCompliance) {
        reasons.push('Sovereign bank identity not stable');
      }
    } else {
      // For supranational entities, check member banks
      const members = await prisma.supranationalEntityMember.findMany({
        where: { entityId, status: 'active' },
        include: { sovereignBank: true },
      });

      ilieCompliance =
        members.length > 0 &&
        members.every(
          (m) => m.sovereignBank.status === 'active' && !!m.sovereignBank.rootSovereignKey
        );

      if (!ilieCompliance) {
        reasons.push('Member banks do not have stable identities');
      }
    }

    // Check reserve adequacy
    // In production, would calculate actual reserve adequacy
    const pools = await prisma.gruReservePool.findMany({
      where: { entityId },
    });

    const totalReserves = pools.reduce(
      (sum, pool) => sum.plus(pool.totalReserves),
      new Decimal(0)
    );

    // Minimum reserve threshold (would be configurable)
    const minReserves = new Decimal(1000000); // 1M base units
    reserveAdequacy = totalReserves.gte(minReserves);

    if (!reserveAdequacy) {
      reasons.push(
        `Insufficient reserves: ${totalReserves.toString()} < ${minReserves.toString()}`
      );
    }

    const eligible =
      smiaCompliance && ilieCompliance && reserveAdequacy;

    return {
      eligible,
      smiaCompliance,
      ilieCompliance,
      reserveAdequacy,
      reasons: reasons.length > 0 ? reasons : undefined,
    };
  }

  /**
   * Get reserve class ID by type
   */
  private async getReserveClassId(
    classType: ReserveClass
  ): Promise<string> {
    const reserveClass = await prisma.gruSupranationalReserveClass.findUnique({
      where: { classType },
    });

    if (!reserveClass) {
      // Create if doesn't exist
      const newClass = await prisma.gruSupranationalReserveClass.create({
        data: {
          reserveClassId: `SR-CLASS-${uuidv4()}`,
          classType,
          className: this.getClassName(classType),
          description: this.getClassDescription(classType),
          roles: this.getClassRoles(classType),
          functions: this.getClassFunctions(classType),
          status: 'active',
        },
      });
      return newClass.reserveClassId;
    }

    return reserveClass.reserveClassId;
  }

  /**
   * Get class name by type
   */
  private getClassName(classType: ReserveClass): string {
    const names: Record<ReserveClass, string> = {
      'SR-1': 'Global Reserve GRU',
      'SR-2': 'Regional Reserve GRU',
      'SR-3': 'Strategic Reserve GRU',
    };
    return names[classType];
  }

  /**
   * Get class description
   */
  private getClassDescription(classType: ReserveClass): string {
    const descriptions: Record<ReserveClass, string> = {
      'SR-1':
        'Global Reserve GRU held by DBIS and multinational monetary alliances',
      'SR-2':
        'Regional Reserve GRU issued to regional unions (EU, AU, ASEAN, GCC, MERCOSUR)',
      'SR-3':
        'Strategic Reserve GRU backed by energy commodities, food security reserves, strategic metals/minerals',
    };
    return descriptions[classType];
  }

  /**
   * Get class roles
   */
  private getClassRoles(classType: ReserveClass): string[] {
    const roles: Record<ReserveClass, string[]> = {
      'SR-1': [
        'Anchor unit for global macro-liquidity',
        'Crisis stabilization',
        'Quantum-synchronizable reserve asset',
      ],
      'SR-2': [
        'Regional reserve pooling',
        'FX corridor stabilization',
        'Cross-border payments harmonization',
      ],
      'SR-3': [
        'Supply-chain stabilization',
        'Long-horizon reserve growth',
        'Crisis-response liquidity',
      ],
    };
    return roles[classType];
  }

  /**
   * Get class functions
   */
  private getClassFunctions(classType: ReserveClass): string[] {
    const functions: Record<ReserveClass, string[]> = {
      'SR-1': ['Global reserve anchor', 'Crisis intervention'],
      'SR-2': [
        'Regional reserve pooling',
        'FX corridor smoothing',
        'Cross-border payments',
      ],
      'SR-3': [
        'Commodity shock absorption',
        'Strategic reserve management',
      ],
    };
    return functions[classType];
  }

  /**
   * Get supranational issuances
   */
  async getSupranationalIssuances(
    entityId?: string,
    reserveClass?: ReserveClass
  ) {
    const where: any = {};
    if (entityId) where.supranationalEntityId = entityId;
    if (reserveClass) where.reserveClass = reserveClass;

    return await prisma.gruIssuance.findMany({
      where,
      include: {
        entity: true,
        legalRegistrations: true,
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  /**
   * Get issuance by ID
   */
  async getIssuance(issuanceId: string) {
    return await prisma.gruIssuance.findUnique({
      where: { issuanceId },
      include: {
        entity: true,
        legalRegistrations: true,
        audits: true,
      },
    });
  }
}

export const gruSupranationalIssuanceService =
  new GruSupranationalIssuanceService();

