// GRU Metaverse Stress Service
// Metaverse/virtual economic stress tests

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, GruIndexCode } from './gru-index.service';


export interface MetaverseStressTestRequest {
  indexCode: GruIndexCode;
  drainPercent?: number; // Percentage of liquidity to drain
  virtualEconomySize?: number; // Size of virtual economy
  avatarAssetExposure?: number; // Exposure to avatar assets
  parameters?: Record<string, unknown>;
}

export interface MetaverseStressResult {
  testId: string;
  liquidityDrained: Decimal;
  remainingLiquidity: Decimal;
  virtualEconomyImpact: Decimal;
  avatarAssetImpact: Decimal;
  passed: boolean;
  impactLevel: string;
}

export class GruMetaverseStressService {
  /**
   * Run metaverse stress test
   * Tests liquidity extraction from metaverse economies and avatar-asset synthetic liquidity drain
   */
  async runMetaverseStressTest(
    request: MetaverseStressTestRequest
  ): Promise<MetaverseStressResult> {
    logger.info('GRU Metaverse Stress: Running metaverse stress test', { request });

    const testId = `GRU-METAVERSE-STRESS-${uuidv4()}`;

    // Get current index value
    const index = await gruIndexService.getIndex(request.indexCode);
    if (!index) {
      throw new Error(`Index not found: ${request.indexCode}`);
    }

    const baseValue = index.currentValue;
    const drainPercent = new Decimal(
      (request.drainPercent || 0.3) / 100
    ); // 30% default drain
    const virtualEconomySize = new Decimal(
      request.virtualEconomySize || 1000000
    );
    const avatarAssetExposure = new Decimal(
      request.avatarAssetExposure || 0.1
    ); // 10% default exposure

    // Simulate liquidity drain from metaverse
    const baseLiquidity = baseValue.times(virtualEconomySize);
    const liquidityDrained = baseLiquidity.times(drainPercent);
    const remainingLiquidity = baseLiquidity.minus(liquidityDrained);

    // Calculate impact on GRU
    const liquidityImpact = liquidityDrained.dividedBy(baseLiquidity);

    // Simulate avatar-asset synthetic liquidity drain
    const avatarAssetLiquidity = baseLiquidity.times(avatarAssetExposure);
    const avatarDrainPercent = drainPercent.times(1.5); // Avatar assets more sensitive
    const avatarLiquidityDrained = avatarAssetLiquidity.times(avatarDrainPercent);
    const avatarAssetImpact = avatarLiquidityDrained.dividedBy(avatarAssetLiquidity);

    // Combined impact
    const combinedImpact = liquidityImpact.plus(avatarAssetImpact);

    // Check if impact is acceptable
    const impactThreshold = new Decimal(0.5); // 50% impact threshold
    const passed = combinedImpact.lessThan(impactThreshold);

    // Determine impact level
    let impactLevel = 'low';
    const impactPercent = combinedImpact.times(100);
    if (impactPercent.greaterThan(40)) {
      impactLevel = 'critical';
    } else if (impactPercent.greaterThan(30)) {
      impactLevel = 'high';
    } else if (impactPercent.greaterThan(20)) {
      impactLevel = 'medium';
    }

    // Create test record
    const test = await prisma.gruStressTest.create({
      data: {
        testId,
        testName: `Metaverse Stress Test: ${request.indexCode}`,
        stressRegime: 'metaverse',
        testType: 'metaverse',
        parameters: request.parameters || {},
        status: 'completed',
        completedAt: new Date(),
      },
    });

    // Save results
    await prisma.gruStressTestResult.create({
      data: {
        resultId: `GRU-RESULT-${uuidv4()}`,
        testId,
        testName: test.testName,
        stressRegime: 'metaverse',
        metricName: 'metaverse_liquidity_impact',
        metricValue: combinedImpact,
        threshold: impactThreshold,
        passed,
        impactLevel,
        details: {
          liquidityDrained: liquidityDrained.toString(),
          remainingLiquidity: remainingLiquidity.toString(),
          virtualEconomyImpact: liquidityImpact.toString(),
          avatarAssetImpact: avatarAssetImpact.toString(),
          drainPercent: drainPercent.toString(),
          virtualEconomySize: virtualEconomySize.toString(),
          avatarAssetExposure: avatarAssetExposure.toString(),
        },
      },
    });

    logger.info('GRU Metaverse Stress: Metaverse stress test completed', {
      testId,
      combinedImpact: combinedImpact.toString(),
      passed,
      impactLevel,
    });

    return {
      testId,
      liquidityDrained,
      remainingLiquidity,
      virtualEconomyImpact: liquidityImpact,
      avatarAssetImpact,
      passed,
      impactLevel,
    };
  }

  /**
   * Simulate liquidity extraction from metaverse
   * Tests impact of large liquidity withdrawals from virtual economies
   */
  async simulateLiquidityExtraction(
    indexCode: GruIndexCode,
    extractionAmount: Decimal
  ): Promise<Decimal> {
    const index = await gruIndexService.getIndex(indexCode);
    if (!index) {
      throw new Error(`Index not found: ${indexCode}`);
    }

    const baseValue = index.currentValue;

    // Simulate impact of liquidity extraction
    // Large extractions reduce available liquidity and increase volatility
    const extractionRatio = extractionAmount.dividedBy(baseValue);
    const volatilityImpact = extractionRatio.times(0.1); // 10% volatility per unit extracted

    const impactedValue = baseValue.times(
      new Decimal(1).minus(volatilityImpact)
    );

    logger.info('GRU Metaverse Stress: Liquidity extraction simulated', {
      indexCode,
      extractionAmount: extractionAmount.toString(),
      volatilityImpact: volatilityImpact.toString(),
      impactedValue: impactedValue.toString(),
    });

    return impactedValue;
  }

  /**
   * Simulate avatar-asset synthetic liquidity drain
   * Tests impact of draining liquidity from avatar assets
   */
  async simulateAvatarAssetDrain(
    indexCode: GruIndexCode,
    drainPercent: Decimal
  ): Promise<Decimal> {
    const index = await gruIndexService.getIndex(indexCode);
    if (!index) {
      throw new Error(`Index not found: ${indexCode}`);
    }

    const baseValue = index.currentValue;

    // Avatar assets have synthetic liquidity that can be drained
    // This creates cascading effects in virtual economies
    const avatarLiquidityMultiplier = new Decimal(2); // Avatar assets have 2x leverage
    const effectiveDrain = drainPercent.times(avatarLiquidityMultiplier);

    const drainedValue = baseValue.times(new Decimal(1).minus(effectiveDrain));

    logger.info('GRU Metaverse Stress: Avatar asset drain simulated', {
      indexCode,
      drainPercent: drainPercent.toString(),
      effectiveDrain: effectiveDrain.toString(),
      drainedValue: drainedValue.toString(),
    });

    return drainedValue;
  }

  /**
   * Get metaverse stress test by ID
   */
  async getMetaverseStressTest(testId: string) {
    return await prisma.gruStressTest.findUnique({
      where: { testId },
      include: {
        results: {
          where: { stressRegime: 'metaverse' },
        },
      },
    });
  }
}

export const gruMetaverseStressService = new GruMetaverseStressService();

