// GLP Service
// GLP contribution tracking
// Multi-source liquidity aggregation
// Tier 1/2/3 withdrawal management
// Automatic liquidity access (Tier 1: <85% liquidity score)
// Assisted access (Tier 2: MSC approval)
// Crisis intervention (Tier 3: SCC activation)

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { liquidityScoreService } from './liquidity-score.service';
import { glpWithdrawalService } from './glp-withdrawal.service';


export interface GlpContributionRequest {
  sovereignBankId: string;
  contributionType: string;
  amount: string;
  currencyCode?: string;
  assetType?: string;
}

export interface GlpWithdrawalRequest {
  sovereignBankId: string;
  amount: string;
  currencyCode?: string;
}

export class GlpService {
  /**
   * Get or create Global Liquidity Pool
   */
  async getOrCreateGlobalPool(): Promise<string> {
    let pool = await prisma.globalLiquidityPool.findFirst({
      where: {},
      orderBy: { createdAt: 'desc' },
    });

    if (!pool) {
      pool = await prisma.globalLiquidityPool.create({
        data: {
          poolId: `GLP-${uuidv4()}`,
          totalLiquidity: new Decimal(0),
          availableLiquidity: new Decimal(0),
          reservedLiquidity: new Decimal(0),
          assetType: 'multi_asset',
        },
      });
    }

    return pool.poolId;
  }

  /**
   * Contribute to GLP
   */
  async contribute(request: GlpContributionRequest): Promise<string> {
    const poolId = await this.getOrCreateGlobalPool();

    const contributionId = `GLP-CONT-${uuidv4()}`;

    // Create contribution
    const contribution = await prisma.glpContribution.create({
      data: {
        contributionId,
        poolId,
        sovereignBankId: request.sovereignBankId,
        contributionType: request.contributionType,
        amount: new Decimal(request.amount),
        currencyCode: request.currencyCode || null,
        assetType: request.assetType || null,
        status: 'pending',
      },
    });

    // Confirm contribution
    await this.confirmContribution(contributionId);

    // Update pool liquidity
    await this.updatePoolLiquidity(poolId);

    return contributionId;
  }

  /**
   * Confirm contribution
   */
  private async confirmContribution(contributionId: string): Promise<void> {
    await prisma.glpContribution.update({
      where: { contributionId },
      data: {
        status: 'confirmed',
        confirmedAt: new Date(),
      },
    });
  }

  /**
   * Update pool liquidity totals
   */
  private async updatePoolLiquidity(poolId: string): Promise<void> {
    // Sum all contributions
    const contributions = await prisma.glpContribution.findMany({
      where: {
        poolId,
        status: 'confirmed',
      },
    });

    const totalLiquidity = contributions.reduce(
      (sum, contrib) => sum.plus(contrib.amount),
      new Decimal(0)
    );

    // Sum reserved liquidity (from pending withdrawals)
    const pendingWithdrawals = await prisma.glpWithdrawal.findMany({
      where: {
        poolId,
        approvalStatus: {
          in: ['pending', 'approved'],
        },
      },
    });

    const reservedLiquidity = pendingWithdrawals.reduce(
      (sum, withdrawal) => sum.plus(withdrawal.amount),
      new Decimal(0)
    );

    const availableLiquidity = totalLiquidity.minus(reservedLiquidity);

    // Update pool
    await prisma.globalLiquidityPool.update({
      where: { poolId },
      data: {
        totalLiquidity,
        reservedLiquidity,
        availableLiquidity,
        lastUpdated: new Date(),
      },
    });
  }

  /**
   * Request withdrawal (handles Tier 1/2/3 automatically)
   */
  async requestWithdrawal(request: GlpWithdrawalRequest): Promise<string> {
    // Get liquidity score
    const liquidityScore = await liquidityScoreService.getLiquidityScore(
      request.sovereignBankId
    );

    // Determine withdrawal tier
    let withdrawalTier: string;
    let triggerCondition: string | undefined;

    if (liquidityScore && liquidityScore.score < 85) {
      // Tier 1: Automatic liquidity access (<85% liquidity score)
      withdrawalTier = 'tier_1_automatic';
      triggerCondition = `<85% liquidity score (${liquidityScore.score})`;
    } else {
      // Tier 2: Assisted liquidity access (requires MSC approval)
      withdrawalTier = 'tier_2_assisted';
      triggerCondition = 'MSC approval required';
    }

    // Create withdrawal request
    const withdrawalId = await glpWithdrawalService.createWithdrawalRequest({
      ...request,
      withdrawalTier,
      triggerCondition,
      liquidityScore: liquidityScore?.score || null,
    });

    // Process Tier 1 automatically
    if (withdrawalTier === 'tier_1_automatic') {
      await glpWithdrawalService.processAutomaticWithdrawal(withdrawalId);
    }

    return withdrawalId;
  }

  /**
   * Request crisis intervention withdrawal (Tier 3)
   */
  async requestCrisisIntervention(
    request: GlpWithdrawalRequest,
    sccActivationId: string
  ): Promise<string> {
    // Tier 3: Crisis-intervention liquidity (SCC activation)
    const withdrawalId = await glpWithdrawalService.createWithdrawalRequest({
      ...request,
      withdrawalTier: 'tier_3_crisis_intervention',
      triggerCondition: `SCC activation: ${sccActivationId}`,
    });

    return withdrawalId;
  }

  /**
   * Get GLP balance
   */
  async getBalance(currencyCode?: string) {
    const pool = await prisma.globalLiquidityPool.findFirst({
      where: {},
      orderBy: { createdAt: 'desc' },
    });

    if (!pool) {
      return {
        totalLiquidity: '0',
        availableLiquidity: '0',
        reservedLiquidity: '0',
      };
    }

    // Filter by currency if specified
    if (currencyCode) {
      const contributions = await prisma.glpContribution.findMany({
        where: {
          poolId: pool.poolId,
          currencyCode,
          status: 'confirmed',
        },
      });

      const total = contributions.reduce(
        (sum, contrib) => sum.plus(contrib.amount),
        new Decimal(0)
      );

      const withdrawals = await prisma.glpWithdrawal.findMany({
        where: {
          poolId: pool.poolId,
          currencyCode,
          approvalStatus: {
            in: ['pending', 'approved'],
          },
        },
      });

      const reserved = withdrawals.reduce(
        (sum, withdrawal) => sum.plus(withdrawal.amount),
        new Decimal(0)
      );

      return {
        totalLiquidity: total.toString(),
        availableLiquidity: total.minus(reserved).toString(),
        reservedLiquidity: reserved.toString(),
        currencyCode,
      };
    }

    return {
      totalLiquidity: pool.totalLiquidity.toString(),
      availableLiquidity: pool.availableLiquidity.toString(),
      reservedLiquidity: pool.reservedLiquidity.toString(),
    };
  }

  /**
   * Get contributions
   */
  async getContributions(
    sovereignBankId?: string,
    contributionType?: string,
    limit: number = 100
  ) {
    return await prisma.glpContribution.findMany({
      where: {
        ...(sovereignBankId && { sovereignBankId }),
        ...(contributionType && { contributionType }),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  /**
   * Get liquidity sources summary
   */
  async getLiquiditySources() {
    const contributions = await prisma.glpContribution.findMany({
      where: {
        status: 'confirmed',
      },
    });

    const sources: Record<string, Decimal> = {};

    for (const contrib of contributions) {
      const type = contrib.contributionType;
      if (!sources[type]) {
        sources[type] = new Decimal(0);
      }
      sources[type] = sources[type].plus(contrib.amount);
    }

    return Object.entries(sources).map(([type, amount]) => ({
      type,
      amount: amount.toString(),
    }));
  }
}

export const glpService = new GlpService();

