import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
import { isProductionEnvironment } from '@/lib/config/env';
import { Result } from '@/lib/contracts/Result';
import type { Service } from '@/lib/contracts/services/Service';
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';

export interface HealthStatus {
  status: 'healthy' | 'degraded' | 'unhealthy';
  timestamp: string;
  dependencies: {
    api: HealthDependencyStatus;
    database: HealthDependencyStatus;
    externalService: HealthDependencyStatus;
  };
  details?: string;
}

export interface HealthDependencyStatus {
  status: 'healthy' | 'degraded' | 'unhealthy';
  latency?: number;
  error?: string;
}

export type HealthRouteServiceError = 'unavailable' | 'degraded' | 'unknown';

export class HealthRouteService implements Service {
  private readonly maxRetries = 3;
  private readonly retryDelay = 100;
  private readonly timeout = 5000;

  async getHealth(): Promise<Result<HealthStatus, HealthRouteServiceError>> {
    const logger = new ConsoleLogger();
    const baseUrl = getWebsiteApiBaseUrl();
    const errorReporter = new EnhancedErrorReporter(logger, {
      showUserNotifications: false,
      logToConsole: true,
      reportToExternal: isProductionEnvironment(),
    });

    try {
      // Check multiple dependencies with retry logic
      const apiHealth = await this.checkApiHealth(baseUrl, errorReporter, logger);
      const databaseHealth = await this.checkDatabaseHealth(errorReporter, logger);
      const externalServiceHealth = await this.checkExternalServiceHealth(errorReporter, logger);

      // Aggregate health status
      const aggregatedStatus = this.aggregateHealthStatus(
        apiHealth,
        databaseHealth,
        externalServiceHealth
      );

      // Make decision based on aggregated status
      const decision = this.makeHealthDecision(aggregatedStatus);

      return Result.ok({
        status: decision,
        timestamp: new Date().toISOString(),
        dependencies: {
          api: apiHealth,
          database: databaseHealth,
          externalService: externalServiceHealth,
        },
      });
    } catch (error) {
      logger.error('HealthRouteService failed', error instanceof Error ? error : undefined, {
        error: error,
      });

      return Result.err('unknown');
    }
  }

  private async checkApiHealth(
    baseUrl: string,
    errorReporter: EnhancedErrorReporter,
    logger: ConsoleLogger
  ): Promise<HealthDependencyStatus> {
    const startTime = Date.now();

    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), this.timeout);

        const response = await fetch(`${baseUrl}/health`, {
          signal: controller.signal,
        });

        clearTimeout(timeoutId);

        const latency = Date.now() - startTime;

        if (response && response.ok) {
          return {
            status: 'healthy',
            latency,
          };
        }

        if (response && response.status >= 500) {
          if (attempt < this.maxRetries) {
            await this.delay(this.retryDelay * attempt);
            continue;
          }
          return {
            status: 'unhealthy',
            latency,
            error: `Server error: ${response.status}`,
          };
        }

        return {
          status: 'degraded',
          latency,
          error: response ? `Client error: ${response.status}` : 'No response received',
        };
      } catch (error) {
        const latency = Date.now() - startTime;

        if (attempt < this.maxRetries && this.isRetryableError(error)) {
          await this.delay(this.retryDelay * attempt);
          continue;
        }

        return {
          status: 'unhealthy',
          latency,
          error: error instanceof Error ? error.message : 'Unknown error',
        };
      }
    }

    return {
      status: 'unhealthy',
      latency: Date.now() - startTime,
      error: 'Max retries exceeded',
    };
  }

  private async checkDatabaseHealth(
    errorReporter: EnhancedErrorReporter,
    logger: ConsoleLogger
  ): Promise<HealthDependencyStatus> {
    const startTime = Date.now();

    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        // Simulate database health check
        // In a real implementation, this would query the database
        await this.delay(50);

        const latency = Date.now() - startTime;

        // Simulate occasional database issues
        if (Math.random() < 0.1 && attempt < this.maxRetries) {
          throw new Error('Database connection timeout');
        }

        return {
          status: 'healthy',
          latency,
        };
      } catch (error) {
        const latency = Date.now() - startTime;

        if (attempt < this.maxRetries && this.isRetryableError(error)) {
          await this.delay(this.retryDelay * attempt);
          continue;
        }

        return {
          status: 'unhealthy',
          latency,
          error: error instanceof Error ? error.message : 'Unknown error',
        };
      }
    }

    return {
      status: 'unhealthy',
      latency: Date.now() - startTime,
      error: 'Max retries exceeded',
    };
  }

  private async checkExternalServiceHealth(
    errorReporter: EnhancedErrorReporter,
    logger: ConsoleLogger
  ): Promise<HealthDependencyStatus> {
    const startTime = Date.now();

    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        // Simulate external service health check
        // In a real implementation, this would call an external API
        await this.delay(100);

        const latency = Date.now() - startTime;

        // Simulate occasional external service issues
        if (Math.random() < 0.05 && attempt < this.maxRetries) {
          throw new Error('External service timeout');
        }

        return {
          status: 'healthy',
          latency,
        };
      } catch (error) {
        const latency = Date.now() - startTime;

        if (attempt < this.maxRetries && this.isRetryableError(error)) {
          await this.delay(this.retryDelay * attempt);
          continue;
        }

        return {
          status: 'degraded',
          latency,
          error: error instanceof Error ? error.message : 'Unknown error',
        };
      }
    }

    return {
      status: 'degraded',
      latency: Date.now() - startTime,
      error: 'Max retries exceeded',
    };
  }

  private aggregateHealthStatus(
    api: HealthDependencyStatus,
    database: HealthDependencyStatus,
    externalService: HealthDependencyStatus
  ): HealthDependencyStatus {
    // If any critical dependency is unhealthy, overall status is unhealthy
    if (api.status === 'unhealthy' || database.status === 'unhealthy') {
      return {
        status: 'unhealthy',
        latency: Math.max(api.latency || 0, database.latency || 0, externalService.latency || 0),
        error: 'Critical dependency failure',
      };
    }

    // If external service is degraded, overall status is degraded
    if (externalService.status === 'degraded') {
      return {
        status: 'degraded',
        latency: Math.max(api.latency || 0, database.latency || 0, externalService.latency || 0),
        error: 'External service degraded',
      };
    }

    // If all dependencies are healthy, overall status is healthy
    return {
      status: 'healthy',
      latency: Math.max(api.latency || 0, database.latency || 0, externalService.latency || 0),
    };
  }

  private makeHealthDecision(aggregatedStatus: HealthDependencyStatus): HealthStatus['status'] {
    // Decision branches based on aggregated status
    if (aggregatedStatus.status === 'unhealthy') {
      return 'unhealthy';
    }

    if (aggregatedStatus.status === 'degraded') {
      return 'degraded';
    }

    // Check latency thresholds
    if (aggregatedStatus.latency && aggregatedStatus.latency > 1000) {
      return 'degraded';
    }

    return 'healthy';
  }

  private isRetryableError(error: unknown): boolean {
    if (error instanceof Error) {
      const message = error.message.toLowerCase();
      return (
        message.includes('timeout') ||
        message.includes('network') ||
        message.includes('connection') ||
        message.includes('unavailable')
      );
    }
    return false;
  }

  private delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
}
