// Service Health Verification Service
// Verifies service health after deployment completion

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

export interface HealthCheck {
  serviceName: string;
  serviceType: 'besu' | 'firefly' | 'database' | 'monitoring';
  endpoint: string;
  expectedStatus?: number;
  healthCheckPath?: string;
}

export interface HealthVerificationResult {
  serviceName: string;
  healthy: boolean;
  status: string;
  responseTime?: number;
  error?: string;
  checks: Array<{
    name: string;
    passed: boolean;
    details?: string;
  }>;
}

export class HealthVerificationService {
  /**
   * Verify service health
   */
  async verifyHealth(checks: HealthCheck[]): Promise<HealthVerificationResult[]> {
    const results: HealthVerificationResult[] = [];

    for (const check of checks) {
      try {
        const result = await this.verifyServiceHealth(check);
        results.push(result);
      } catch (error) {
        logger.error('Health verification failed', {
          serviceName: check.serviceName,
          error: error instanceof Error ? error.message : 'Unknown error',
        });

        results.push({
          serviceName: check.serviceName,
          healthy: false,
          status: 'unhealthy',
          error: error instanceof Error ? error.message : 'Unknown error',
          checks: [],
        });
      }
    }

    return results;
  }

  /**
   * Verify a single service health
   */
  private async verifyServiceHealth(check: HealthCheck): Promise<HealthVerificationResult> {
    const checks: HealthVerificationResult['checks'] = [];
    const startTime = Date.now();

    // 1. Connectivity check
    const connectivityCheck = await this.checkConnectivity(check);
    checks.push(connectivityCheck);

    if (!connectivityCheck.passed) {
      return {
        serviceName: check.serviceName,
        healthy: false,
        status: 'unreachable',
        responseTime: Date.now() - startTime,
        checks,
      };
    }

    // 2. Health endpoint check
    const healthCheck = await this.checkHealthEndpoint(check);
    checks.push(healthCheck);

    // 3. Service-specific checks
    const serviceChecks = await this.checkServiceSpecific(check);
    checks.push(...serviceChecks);

    const allPassed = checks.every((c) => c.passed);
    const responseTime = Date.now() - startTime;

    return {
      serviceName: check.serviceName,
      healthy: allPassed,
      status: allPassed ? 'healthy' : 'degraded',
      responseTime,
      checks,
    };
  }

  /**
   * Check connectivity
   */
  private async checkConnectivity(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    try {
      const response = await retryWithBackoff(
        async () => {
          return await fetch(check.endpoint, {
            method: 'GET',
            signal: AbortSignal.timeout(5000),
          });
        },
        {
          maxRetries: 2,
          initialDelayMs: 1000,
        }
      );

      return {
        name: 'connectivity',
        passed: response.ok,
        details: `HTTP ${response.status}`,
      };
    } catch (error) {
      return {
        name: 'connectivity',
        passed: false,
        details: error instanceof Error ? error.message : 'Connection failed',
      };
    }
  }

  /**
   * Check health endpoint
   */
  private async checkHealthEndpoint(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    const healthPath = check.healthCheckPath || '/health';
    const healthUrl = `${check.endpoint}${healthPath}`;

    try {
      const response = await fetch(healthUrl, {
        method: 'GET',
        signal: AbortSignal.timeout(5000),
      });

      const data = await response.json().catch(() => ({}));

      return {
        name: 'health_endpoint',
        passed: response.ok && (data.status === 'healthy' || data.status === 'ok'),
        details: `Status: ${data.status || response.status}`,
      };
    } catch (error) {
      return {
        name: 'health_endpoint',
        passed: false,
        details: error instanceof Error ? error.message : 'Health check failed',
      };
    }
  }

  /**
   * Service-specific checks
   */
  private async checkServiceSpecific(check: HealthCheck): Promise<HealthVerificationResult['checks'][]> {
    const checks: HealthVerificationResult['checks'][] = [];

    switch (check.serviceType) {
      case 'besu':
        checks.push(await this.checkBesuHealth(check));
        break;
      case 'firefly':
        checks.push(await this.checkFireFlyHealth(check));
        break;
      case 'database':
        checks.push(await this.checkDatabaseHealth(check));
        break;
      case 'monitoring':
        checks.push(await this.checkMonitoringHealth(check));
        break;
    }

    return checks;
  }

  /**
   * Check Besu health
   */
  private async checkBesuHealth(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    try {
      const response = await fetch(check.endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          method: 'eth_blockNumber',
          params: [],
          id: 1,
        }),
        signal: AbortSignal.timeout(5000),
      });

      const data = await response.json();

      return {
        name: 'besu_rpc',
        passed: response.ok && data.result !== undefined,
        details: data.result ? `Block: ${parseInt(data.result, 16)}` : 'RPC call failed',
      };
    } catch (error) {
      return {
        name: 'besu_rpc',
        passed: false,
        details: error instanceof Error ? error.message : 'Besu RPC check failed',
      };
    }
  }

  /**
   * Check FireFly health
   */
  private async checkFireFlyHealth(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    try {
      const response = await fetch(`${check.endpoint}/api/v1/status`, {
        method: 'GET',
        signal: AbortSignal.timeout(5000),
      });

      const data = await response.json();

      return {
        name: 'firefly_status',
        passed: response.ok && data.ready === true,
        details: data.ready ? 'FireFly ready' : 'FireFly not ready',
      };
    } catch (error) {
      return {
        name: 'firefly_status',
        passed: false,
        details: error instanceof Error ? error.message : 'FireFly status check failed',
      };
    }
  }

  /**
   * Check database health
   */
  private async checkDatabaseHealth(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    // Database health check would depend on database type
    return {
      name: 'database_connection',
      passed: true,
      details: 'Database connection check - implementation pending',
    };
  }

  /**
   * Check monitoring health
   */
  private async checkMonitoringHealth(check: HealthCheck): Promise<HealthVerificationResult['checks'][0]> {
    try {
      const response = await fetch(`${check.endpoint}/metrics`, {
        method: 'GET',
        signal: AbortSignal.timeout(5000),
      });

      return {
        name: 'monitoring_metrics',
        passed: response.ok,
        details: response.ok ? 'Metrics endpoint accessible' : 'Metrics endpoint not accessible',
      };
    } catch (error) {
      return {
        name: 'monitoring_metrics',
        passed: false,
        details: error instanceof Error ? error.message : 'Monitoring metrics check failed',
      };
    }
  }
}

export const healthVerificationService = new HealthVerificationService();
