// Resource Allocator Service
// Allocates infrastructure resources for IRU

import { DeploymentConfig } from '../types/common.types';

export interface ResourceAllocationRequest {
  capacityTier: number;
  institutionalType: string;
  deploymentConfig?: DeploymentConfig;
  subscriptionId?: string;
}

export interface ResourceAllocation {
  containers: Array<{
    name: string;
    type: string;
    resources: {
      cpu: number;
      memory: number;
      disk: number;
    };
    network: {
      ip: string;
      vlan?: number;
    };
  }>;
  network: {
    vlan: number;
    subnet: string;
    gateway: string;
  };
  storage: {
    total: number;
    pools: string[];
  };
}

export class ResourceAllocator {
  /**
   * Allocate resources
   */
  async allocate(request: ResourceAllocationRequest): Promise<ResourceAllocation> {
    // Determine resource requirements based on capacity tier
    const resourceSpecs = this.getResourceSpecs(request.capacityTier);

    // Allocate network first (needed for container IPs)
    const subscriptionId = request.subscriptionId || `SUB-${Date.now()}`;
    const network = await this.allocateNetwork(request.capacityTier, subscriptionId);

    // Allocate containers (with IPs from IPAM)
    const containers = await this.allocateContainers(resourceSpecs, subscriptionId, network);

    // Allocate storage
    const storage = this.allocateStorage(resourceSpecs);

    return {
      containers,
      network,
      storage,
    };
  }

  /**
   * Get resource specifications by tier
   */
  private getResourceSpecs(capacityTier: number): {
    besuSentry: { cpu: number; memory: number; disk: number };
    fireflyCore: { cpu: number; memory: number; disk: number };
    fireflyDb: { cpu: number; memory: number; disk: number };
    monitoring: { cpu: number; memory: number; disk: number };
  } {
    const specs: Record<number, any> = {
      1: {
        // Tier 1: Central Banks
        besuSentry: { cpu: 4, memory: 8, disk: 100 },
        fireflyCore: { cpu: 4, memory: 8, disk: 50 },
        fireflyDb: { cpu: 2, memory: 4, disk: 200 },
        monitoring: { cpu: 1, memory: 2, disk: 20 },
      },
      2: {
        // Tier 2: Settlement Banks
        besuSentry: { cpu: 2, memory: 4, disk: 50 },
        fireflyCore: { cpu: 2, memory: 4, disk: 30 },
        fireflyDb: { cpu: 1, memory: 2, disk: 100 },
        monitoring: { cpu: 1, memory: 1, disk: 10 },
      },
      3: {
        // Tier 3: Commercial Banks
        besuSentry: { cpu: 2, memory: 4, disk: 50 },
        fireflyCore: { cpu: 2, memory: 4, disk: 30 },
        fireflyDb: { cpu: 1, memory: 2, disk: 100 },
        monitoring: { cpu: 1, memory: 1, disk: 10 },
      },
      4: {
        // Tier 4: DFIs
        besuSentry: { cpu: 1, memory: 2, disk: 30 },
        fireflyCore: { cpu: 1, memory: 2, disk: 20 },
        fireflyDb: { cpu: 1, memory: 2, disk: 50 },
        monitoring: { cpu: 1, memory: 1, disk: 10 },
      },
      5: {
        // Tier 5: Special Entities
        besuSentry: { cpu: 1, memory: 2, disk: 30 },
        fireflyCore: { cpu: 1, memory: 2, disk: 20 },
        fireflyDb: { cpu: 1, memory: 2, disk: 50 },
        monitoring: { cpu: 1, memory: 1, disk: 10 },
      },
    };

    return specs[capacityTier] || specs[3];
  }

  /**
   * Allocate containers
   */
  private async allocateContainers(
    specs: any,
    subscriptionId: string,
    network: ResourceAllocation['network']
  ): Promise<ResourceAllocation['containers']> {
    const containers: ResourceAllocation['containers'] = [];

    // Allocate IPs via IPAM
    const { ipamService } = await import('@/core/iru/ipam/ipam.service');
    const networkAllocations = await ipamService.allocateNetwork(subscriptionId, 4);

    // Besu Sentry container
    containers.push({
      name: 'lxc-besu-sentry',
      type: 'besu-sentry',
      resources: {
        cpu: specs.besuSentry.cpu,
        memory: specs.besuSentry.memory * 1024, // GB to MB
        disk: specs.besuSentry.disk * 1024, // GB to MB
      },
      network: {
        ip: networkAllocations[0]?.ipAddress || await this.generateIP(subscriptionId),
        vlan: network.vlan,
      },
    });

    // FireFly Core container
    containers.push({
      name: 'lxc-firefly-core',
      type: 'firefly-core',
      resources: {
        cpu: specs.fireflyCore.cpu,
        memory: specs.fireflyCore.memory * 1024,
        disk: specs.fireflyCore.disk * 1024,
      },
      network: {
        ip: networkAllocations[1]?.ipAddress || await this.generateIP(subscriptionId),
        vlan: network.vlan,
      },
    });

    // FireFly Database container
    containers.push({
      name: 'lxc-firefly-db',
      type: 'firefly-db',
      resources: {
        cpu: specs.fireflyDb.cpu,
        memory: specs.fireflyDb.memory * 1024,
        disk: specs.fireflyDb.disk * 1024,
      },
      network: {
        ip: networkAllocations[2]?.ipAddress || await this.generateIP(subscriptionId),
        vlan: network.vlan,
      },
    });

    // Monitoring container
    containers.push({
      name: 'lxc-monitoring',
      type: 'monitoring',
      resources: {
        cpu: specs.monitoring.cpu,
        memory: specs.monitoring.memory * 1024,
        disk: specs.monitoring.disk * 1024,
      },
      network: {
        ip: networkAllocations[3]?.ipAddress || await this.generateIP(subscriptionId),
        vlan: network.vlan,
      },
    });

    return containers;
  }

  /**
   * Allocate network
   */
  private async allocateNetwork(capacityTier: number, subscriptionId: string): Promise<ResourceAllocation['network']> {
    // Integrate with IPAM system
    const { ipamService } = await import('@/core/iru/ipam/ipam.service');
    
    // Allocate network resources via IPAM
    const allocations = await ipamService.allocateNetwork(subscriptionId, 4); // 4 containers
    
    if (allocations.length === 0) {
      // Fallback to default network if IPAM fails
      const vlan = 100 + capacityTier;
      const subnet = `10.${capacityTier}.1.0/24`;
      const gateway = `10.${capacityTier}.1.1`;
      return { vlan, subnet, gateway };
    }

    // Use first allocation for network config
    const firstAllocation = allocations[0];
    return {
      vlan: firstAllocation.vlan,
      subnet: firstAllocation.subnet,
      gateway: firstAllocation.gateway,
    };
  }

  /**
   * Allocate storage
   */
  private allocateStorage(specs: {
    besuSentry: { cpu: number; memory: number; disk: number };
    fireflyCore: { cpu: number; memory: number; disk: number };
    fireflyDb: { cpu: number; memory: number; disk: number };
    monitoring: { cpu: number; memory: number; disk: number };
  }): ResourceAllocation['storage'] {
    const total =
      specs.besuSentry.disk +
      specs.fireflyCore.disk +
      specs.fireflyDb.disk +
      specs.monitoring.disk;

    return {
      total: total * 1024, // GB to MB
      pools: ['local-lvm'], // Default storage pool
    };
  }

  /**
   * Generate IP address using IPAM
   */
  private async generateIP(subscriptionId: string): Promise<string> {
    // Integrate with IPAM system
    const { ipamService } = await import('@/core/iru/ipam/ipam.service');
    
    try {
      const allocations = await ipamService.allocateNetwork(subscriptionId, 1);
      return allocations[0]?.ipAddress || this.generateFallbackIP();
    } catch (error) {
      // Fallback if IPAM fails
      return this.generateFallbackIP();
    }
  }

  /**
   * Generate fallback IP address
   */
  private generateFallbackIP(): string {
    const octet2 = Math.floor(Math.random() * 255);
    const octet3 = Math.floor(Math.random() * 255);
    const octet4 = Math.floor(Math.random() * 254) + 1;
    return `10.${octet2}.${octet3}.${octet4}`;
  }
}

export const resourceAllocator = new ResourceAllocator();
