// Off-Ramp Service
// Metaverse → Real-world conversion: Tokenized Assets → Fiat, CBDC, GRU, SSU
// Supplement B: MetaverseDubai Integration Framework

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 { dsezService } from '../d-sez/d-sez.service';
import { rampValidationService } from './ramp-validation.service';


export interface OffRampRequest {
  dsezId: string;
  metaverseNodeId: string;
  sourceType: 'virtual_currency' | 'tokenized_asset';
  targetType: 'fiat' | 'cbdc' | 'gru' | 'ssu';
  amount: string;
  currencyCode: string;
  assetId?: string; // For tokenized assets
  sourceBankId?: string;
  destinationBankId?: string;
  metadata?: Record<string, unknown>;
}

export interface OffRampResult {
  rampId: string;
  status: string;
  exchangeRate?: number;
  realWorldAmount?: string;
  validationHash?: string;
}

export class OffRampService {
  /**
   * Execute off-ramp: Metaverse → Real-world
   * Supports: Tokenized Assets → Fiat, CBDC, GRU, SSU
   */
  async executeOffRamp(request: OffRampRequest): Promise<OffRampResult> {
    logger.info('Off-Ramp: Executing off-ramp', { request });

    // Step 1: Verify D-SEZ exists and is active
    const dsez = await dsezService.getDsez(request.dsezId);
    if (!dsez || dsez.status !== 'active') {
      throw new Error(`D-SEZ not found or inactive: ${request.dsezId}`);
    }

    // Step 2: Verify liquidity flow is enabled
    if (!dsez.liquidityFlowEnabled) {
      throw new Error('Liquidity flow not enabled for this D-SEZ');
    }

    // Step 3: If tokenized asset, verify ownership
    if (request.sourceType === 'tokenized_asset' && request.assetId) {
      const asset = await prisma.metaverseAsset.findUnique({
        where: { assetId: request.assetId },
      });

      if (!asset) {
        throw new Error(`Asset not found: ${request.assetId}`);
      }

      if (asset.status !== 'active') {
        throw new Error(`Asset not available for off-ramp: ${asset.status}`);
      }
    }

    // Step 4: Calculate exchange rate
    const exchangeRate = await this.calculateExchangeRate(
      request.sourceType,
      request.targetType,
      request.currencyCode
    );

    // Step 5: Calculate real-world amount
    const realWorldAmount = (
      parseFloat(request.amount) * exchangeRate
    ).toFixed(8);

    // Step 6: Validate transaction
    const validation = await rampValidationService.validateOffRamp({
      dsezId: request.dsezId,
      sourceType: request.sourceType,
      targetType: request.targetType,
      amount: request.amount,
      currencyCode: request.currencyCode,
      assetId: request.assetId,
      destinationBankId: request.destinationBankId,
    });

    if (!validation.validated) {
      throw new Error(`Off-ramp validation failed: ${validation.reason}`);
    }

    // Step 7: Create ramp transaction
    const rampId = `OFF-RAMP-${uuidv4()}`;
    const rampTransaction = await prisma.metaverseRampTransaction.create({
      data: {
        rampId,
        dsezId: request.dsezId,
        metaverseNodeId: request.metaverseNodeId,
        rampType: 'off_ramp',
        sourceType: request.sourceType,
        targetType: request.targetType,
        amount: new Decimal(request.amount),
        currencyCode: request.currencyCode,
        sourceBankId: request.sourceBankId || null,
        destinationBankId: request.destinationBankId || null,
        exchangeRate: new Decimal(exchangeRate),
        status: 'processing',
        complianceCheck: validation.complianceCheck,
        validationHash: validation.validationHash || null,
      },
    });

    // Step 8: Execute conversion (in a full implementation, this would interact with CBDC/GRU/SSU systems)
    // For now, we'll mark it as completed
    await prisma.metaverseRampTransaction.update({
      where: { rampId },
      data: {
        status: 'completed',
        processedAt: new Date(),
      },
    });

    logger.info('Off-Ramp: Off-ramp completed', {
      rampId,
      amount: request.amount,
      realWorldAmount,
    });

    return {
      rampId,
      status: 'completed',
      exchangeRate,
      realWorldAmount,
      validationHash: validation.validationHash,
    };
  }

  /**
   * Calculate exchange rate between source and target types
   */
  private async calculateExchangeRate(
    sourceType: string,
    targetType: string,
    currencyCode: string
  ): Promise<number> {
    // In a full implementation, this would:
    // 1. Query virtual currency rates
    // 2. Query tokenized asset valuations
    // 3. Query FX rates for target currency
    // 4. Apply off-ramp fees/discounts

    // For now, return a default rate
    // Virtual to real-world typically has a slight discount
    const baseRate = 1.0;
    const offRampDiscount = 0.01; // 1% discount for off-ramp

    return baseRate - offRampDiscount;
  }

  /**
   * Get off-ramp transaction by ID
   */
  async getOffRampTransaction(rampId: string) {
    return await prisma.metaverseRampTransaction.findUnique({
      where: { rampId },
      include: {
        dsez: true,
        node: true,
      },
    });
  }

  /**
   * Get off-ramp transactions for D-SEZ
   */
  async getOffRampTransactionsForDsez(dsezId: string) {
    return await prisma.metaverseRampTransaction.findMany({
      where: {
        dsezId,
        rampType: 'off_ramp',
      },
      orderBy: { createdAt: 'desc' },
    });
  }
}

export const offRampService = new OffRampService();

