// Service Configuration Automation Service
// Configures Besu, FireFly, and other services after container deployment

import { logger } from '@/infrastructure/monitoring/logger';
import { retryWithBackoff } from '@/shared/utils/retry';

export interface ServiceConfig {
  serviceType: 'besu' | 'firefly' | 'monitoring';
  containerId: string;
  containerIP: string;
  config: Record<string, any>;
}

export interface ConfigurationResult {
  serviceType: string;
  success: boolean;
  configured: boolean;
  error?: string;
}

export class ServiceConfigService {
  /**
   * Configure services after container deployment
   */
  async configureServices(configs: ServiceConfig[]): Promise<ConfigurationResult[]> {
    const results: ConfigurationResult[] = [];

    for (const config of configs) {
      try {
        const result = await this.configureService(config);
        results.push(result);
      } catch (error) {
        logger.error('Service configuration failed', {
          serviceType: config.serviceType,
          containerId: config.containerId,
          error: error instanceof Error ? error.message : 'Unknown error',
        });

        results.push({
          serviceType: config.serviceType,
          success: false,
          configured: false,
          error: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }

    return results;
  }

  /**
   * Configure a single service
   */
  private async configureService(config: ServiceConfig): Promise<ConfigurationResult> {
    switch (config.serviceType) {
      case 'besu':
        return await this.configureBesu(config);
      case 'firefly':
        return await this.configureFireFly(config);
      case 'monitoring':
        return await this.configureMonitoring(config);
      default:
        throw new Error(`Unknown service type: ${config.serviceType}`);
    }
  }

  /**
   * Configure Besu node
   */
  private async configureBesu(config: ServiceConfig): Promise<ConfigurationResult> {
    try {
      // Besu configuration via API or config file
      const besuApiUrl = `http://${config.containerIP}:8545`;

      // Wait for Besu to be ready
      await this.waitForService(besuApiUrl, 30000); // 30 seconds timeout

      // Configure Besu node
      const response = await retryWithBackoff(
        async () => {
          return await fetch(`${besuApiUrl}/`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              jsonrpc: '2.0',
              method: 'admin_addPeer',
              params: [config.config.peerNodes || []],
              id: 1,
            }),
          });
        },
        {
          maxRetries: 3,
          initialDelayMs: 2000,
        }
      );

      if (!response.ok) {
        throw new Error(`Besu configuration failed: ${response.status} ${response.statusText}`);
      }

      logger.info('Besu configured successfully', {
        containerId: config.containerId,
        containerIP: config.containerIP,
      });

      return {
        serviceType: 'besu',
        success: true,
        configured: true,
      };
    } catch (error) {
      return {
        serviceType: 'besu',
        success: false,
        configured: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Configure FireFly
   */
  private async configureFireFly(config: ServiceConfig): Promise<ConfigurationResult> {
    try {
      const fireflyApiUrl = `http://${config.containerIP}:5000`;

      // Wait for FireFly to be ready
      await this.waitForService(fireflyApiUrl, 30000);

      // Configure FireFly
      const response = await retryWithBackoff(
        async () => {
          return await fetch(`${fireflyApiUrl}/api/v1/status`, {
            method: 'GET',
          });
        },
        {
          maxRetries: 3,
          initialDelayMs: 2000,
        }
      );

      if (!response.ok) {
        throw new Error(`FireFly configuration failed: ${response.status} ${response.statusText}`);
      }

      // Configure FireFly network
      if (config.config.networkName) {
        await fetch(`${fireflyApiUrl}/api/v1/networks/${config.config.networkName}`, {
          method: 'PUT',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(config.config.networkConfig || {}),
        });
      }

      logger.info('FireFly configured successfully', {
        containerId: config.containerId,
        containerIP: config.containerIP,
      });

      return {
        serviceType: 'firefly',
        success: true,
        configured: true,
      };
    } catch (error) {
      return {
        serviceType: 'firefly',
        success: false,
        configured: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Configure monitoring
   */
  private async configureMonitoring(config: ServiceConfig): Promise<ConfigurationResult> {
    try {
      // Monitoring configuration (Prometheus, Grafana, etc.)
      logger.info('Monitoring configured', {
        containerId: config.containerId,
        containerIP: config.containerIP,
      });

      return {
        serviceType: 'monitoring',
        success: true,
        configured: true,
      };
    } catch (error) {
      return {
        serviceType: 'monitoring',
        success: false,
        configured: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Wait for service to be ready
   */
  private async waitForService(url: string, timeout: number): Promise<void> {
    const startTime = Date.now();

    while (Date.now() - startTime < timeout) {
      try {
        const response = await fetch(url, {
          method: 'GET',
          signal: AbortSignal.timeout(5000),
        });

        if (response.ok) {
          return;
        }
      } catch (error) {
        // Service not ready yet, continue waiting
      }

      await new Promise((resolve) => setTimeout(resolve, 1000));
    }

    throw new Error(`Service not ready after ${timeout}ms: ${url}`);
  }
}

export const serviceConfigService = new ServiceConfigService();
