// GAS Routing Service
// Smart routing using SIRE + CASO + ARIFX (placeholder)

import { logger } from '@/infrastructure/monitoring/logger';
import { sireRoutingService } from '@/core/settlement/sire/sire-routing.service';
import { casoRoutingService } from '@/core/settlement/caso/caso-routing.service';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import prisma from '@/shared/database/prisma';

export interface GasRoutingRequest {
  sourceBankId: string;
  destinationBankId: string;
  amount: string;
  currencyCode: string;
  assetType: string;
  networkType?: 'classical' | 'cbdc' | 'commodity' | 'security' | 'quantum' | 'multiversal';
  optimizeFor?: 'cost' | 'latency' | 'dimensional_alignment';
}

export interface GasRoutingResult {
  routeId: string;
  optimalRoute: any;
  routingEngine: 'sire' | 'caso' | 'arifx' | 'hybrid';
  cost: Decimal;
  latency: number;
  dimensionalAlignment: number;
}

export class GasRoutingService {
  /**
   * Calculate optimal route using SIRE + CASO + ARIFX
   * Optimizes for cost, latency, dimensional alignment
   */
  async calculateOptimalRoute(
    request: GasRoutingRequest
  ): Promise<GasRoutingResult> {
    logger.info('GAS: Calculating optimal route', { request });

    // Step 1: Get routes from SIRE
    const sireRoute = await this.getSireRoute(request);

    // Step 2: Get routes from CASO
    const casoRoute = await this.getCasoRoute(request);

    // Step 3: Get routes from ARIFX (placeholder - future module)
    const arifxRoute = await this.getArifxRoute(request);

    // Step 4: Evaluate all routes based on optimization criteria
    const routes = [sireRoute, casoRoute, arifxRoute].filter((r) => r !== null);

    if (routes.length === 0) {
      throw new Error('No routes available from routing engines');
    }

    // Step 5: Select optimal route based on optimization criteria
    const optimalRoute = this.selectOptimalRoute(
      routes,
      request.optimizeFor || 'cost'
    );

    // Step 6: Save routing decision
    const routeId = await this.saveGasRoutingDecision(request, optimalRoute);

    logger.info('GAS: Optimal route calculated', {
      routeId,
      routingEngine: optimalRoute.routingEngine,
    });

    return {
      routeId,
      optimalRoute: optimalRoute.route,
      routingEngine: optimalRoute.routingEngine,
      cost: optimalRoute.cost,
      latency: optimalRoute.latency,
      dimensionalAlignment: optimalRoute.dimensionalAlignment,
    };
  }

  /**
   * Get route from SIRE
   */
  private async getSireRoute(
    request: GasRoutingRequest
  ): Promise<{
    routingEngine: 'sire';
    route: any;
    cost: Decimal;
    latency: number;
    dimensionalAlignment: number;
  } | null> {
    try {
      const routeId = await sireRoutingService.calculateOptimalRoute({
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: request.amount,
        currencyCode: request.currencyCode,
      });

      const decision = await sireRoutingService.getOptimalRoute(routeId);
      if (!decision) return null;

      return {
        routingEngine: 'sire',
        route: decision.optimalRoute,
        cost: decision.totalCost,
        latency: 50, // Estimated latency for SIRE routes
        dimensionalAlignment: 0.8, // SIRE focuses on classical networks
      };
    } catch (error) {
      logger.warn('GAS: SIRE route calculation failed', { error });
      return null;
    }
  }

  /**
   * Get route from CASO
   */
  private async getCasoRoute(
    request: GasRoutingRequest
  ): Promise<{
    routingEngine: 'caso';
    route: any;
    cost: Decimal;
    latency: number;
    dimensionalAlignment: number;
  } | null> {
    try {
      const result = await casoRoutingService.calculateAndApplyRoute({
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: request.amount,
        currencyCode: request.currencyCode,
        assetType: request.assetType,
      });

      // Get CASO route details
      const casoRoute = await prisma.casoRoute.findUnique({
        where: { routeId: result.routeId },
      });

      if (!casoRoute) return null;

      return {
        routingEngine: 'caso',
        route: casoRoute.routePath,
        cost: casoRoute.totalCost,
        latency: 40, // Estimated latency for CASO routes
        dimensionalAlignment: 0.7, // CASO focuses on cross-border optimization
      };
    } catch (error) {
      logger.warn('GAS: CASO route calculation failed', { error });
      return null;
    }
  }

  /**
   * Get route from ARIFX (placeholder - future module)
   */
  private async getArifxRoute(
    request: GasRoutingRequest
  ): Promise<{
    routingEngine: 'arifx';
    route: any;
    cost: Decimal;
    latency: number;
    dimensionalAlignment: number;
  } | null> {
    // ARIFX is a future module - placeholder implementation
    logger.info('GAS: ARIFX route calculation (placeholder)', { request });

    // Return null for now - ARIFX will be implemented in future
    return null;
  }

  /**
   * Select optimal route based on optimization criteria
   */
  private selectOptimalRoute(
    routes: Array<{
      routingEngine: 'sire' | 'caso' | 'arifx';
      route: any;
      cost: Decimal;
      latency: number;
      dimensionalAlignment: number;
    }>,
    optimizeFor: 'cost' | 'latency' | 'dimensional_alignment'
  ): {
    routingEngine: 'sire' | 'caso' | 'arifx' | 'hybrid';
    route: any;
    cost: Decimal;
    latency: number;
    dimensionalAlignment: number;
  } {
    if (routes.length === 1) {
      return routes[0];
    }

    switch (optimizeFor) {
      case 'cost':
        return routes.reduce((min, current) =>
          current.cost.lt(min.cost) ? current : min
        );

      case 'latency':
        return routes.reduce((min, current) =>
          current.latency < min.latency ? current : min
        );

      case 'dimensional_alignment':
        return routes.reduce((max, current) =>
          current.dimensionalAlignment > max.dimensionalAlignment
            ? current
            : max
        );

      default:
        // Hybrid: balance all factors
        const scoredRoutes = routes.map((route) => ({
          ...route,
          score:
            route.cost.toNumber() * 0.4 +
            route.latency * 0.3 +
            (1 - route.dimensionalAlignment) * 100 * 0.3,
        }));

        return scoredRoutes.reduce((min, current) =>
          current.score < min.score ? current : min
        );
    }
  }

  /**
   * Save GAS routing decision
   */
  private async saveGasRoutingDecision(
    request: GasRoutingRequest,
    optimalRoute: {
      routingEngine: 'sire' | 'caso' | 'arifx' | 'hybrid';
      route: any;
      cost: Decimal;
      latency: number;
      dimensionalAlignment: number;
    }
  ): Promise<string> {
    const routeId = `GAS-ROUTE-${uuidv4()}`;

    await prisma.gasRoutingDecision.create({
      data: {
        routeId,
        settlementId: null, // Will be set when settlement is created
        sourceBankId: request.sourceBankId,
        destinationBankId: request.destinationBankId,
        amount: new Decimal(request.amount),
        currencyCode: request.currencyCode,
        assetType: request.assetType,
        networkType: request.networkType || 'classical',
        routingEngine: optimalRoute.routingEngine,
        optimalRoute: optimalRoute.route as any,
        cost: optimalRoute.cost,
        latency: optimalRoute.latency,
        dimensionalAlignment: optimalRoute.dimensionalAlignment,
        status: 'active',
      },
    });

    return routeId;
  }

  /**
   * Get routing history
   */
  async getRoutingHistory(
    sourceBankId?: string,
    destinationBankId?: string,
    limit: number = 100
  ) {
    return await prisma.gasRoutingDecision.findMany({
      where: {
        ...(sourceBankId && { sourceBankId }),
        ...(destinationBankId && { destinationBankId }),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }
}

export const gasRoutingService = new GasRoutingService();

