/**
 * Self-Healing Example
 * Demonstrates the integration of health monitoring and recovery mechanisms
 */

import {
  HealthCheckEngine,
  defaultHealthCheckEngine,
  OperationalContext,
  MarineEnvironmentStatus,
  HealthMonitoringEvent,
  HealthStatus
} from '../index';

import {
  GPSHealthCheck,
  createGPSHealthCheck,
  GPSData
} from '../marine/GPSHealthCheck';

import {
  RecoveryOrchestrator,
  defaultRecoveryOrchestrator
} from '../recovery/RecoveryOrchestrator';

import {
  GPSRecalibrationAction,
  createGPSRecalibrationAction
} from '../recovery/actions/GPSRecalibrationAction';

import {
  registerGPSRecoveryPolicies
} from '../recovery/policies/GPSRecoveryPolicy';

/**
 * Self-healing example for marine systems
 */
export class SelfHealingExample {
  private healthEngine: HealthCheckEngine;
  private recoveryOrchestrator: RecoveryOrchestrator;
  private gpsHealthCheck!: GPSHealthCheck;
  private gpsRecalibrationAction!: GPSRecalibrationAction;
  
  // Simulated GPS state
  private gpsState = {
    satelliteCount: 8,
    hdop: 1.2,
    fix: '3d' as '3d' | '2d' | 'none',
    isCalibrated: true
  };
  
  constructor() {
    this.healthEngine = defaultHealthCheckEngine;
    this.recoveryOrchestrator = defaultRecoveryOrchestrator;
    
    // Set up event handling
    this.setupEventHandling();
    
    // Initialize health checks and recovery actions
    this.initializeHealthChecks();
    this.initializeRecoveryActions();
  }
  
  /**
   * Initialize health checks
   */
  private initializeHealthChecks(): void {
    // Create GPS health check
    this.gpsHealthCheck = createGPSHealthCheck(
      this.mockGPSDataProvider.bind(this)
    );
    
    // Register with health engine
    this.healthEngine.registerHealthCheck(this.gpsHealthCheck);
  }
  
  /**
   * Initialize recovery actions and policies
   */
  private initializeRecoveryActions(): void {
    // Create GPS recalibration action
    this.gpsRecalibrationAction = createGPSRecalibrationAction({
      resetSatelliteTracking: async () => {
        console.log('🛠️ GPS: Resetting satellite tracking');
        await this.wait(1000);
        return true;
      },
      clearAlmanac: async () => {
        console.log('🛠️ GPS: Clearing almanac data');
        await this.wait(1000);
        return true;
      },
      resetHDOPThresholds: async () => {
        console.log('🛠️ GPS: Resetting HDOP thresholds');
        await this.wait(1000);
        return true;
      },
      forceColdStart: async () => {
        console.log('🛠️ GPS: Forcing cold start');
        await this.wait(2000);
        return true;
      },
      waitForSatellites: async (timeout: number) => {
        console.log(`🛠️ GPS: Waiting for satellites (timeout: ${timeout}s)`);
        await this.wait(2000);
        
        // Recalibration improves satellite count
        this.gpsState.satelliteCount = Math.min(12, this.gpsState.satelliteCount + 4);
        this.gpsState.hdop = Math.max(0.8, this.gpsState.hdop - 0.4);
        this.gpsState.isCalibrated = true;
        
        return this.gpsState.satelliteCount;
      }
    });
    
    // Register recovery action
    this.recoveryOrchestrator.registerRecoveryAction(this.gpsRecalibrationAction);
    
    // Register recovery policies
    registerGPSRecoveryPolicies(
      policy => this.recoveryOrchestrator.registerRecoveryPolicy(policy)
    );
  }
  
  /**
   * Set up event handling
   */
  private setupEventHandling(): void {
    // Listen for health monitoring events
    this.healthEngine.onEvent((event: HealthMonitoringEvent) => {
      console.log(`[${event.timestamp.toISOString()}] Health Event: ${event.eventType}`);
      console.log(`  System: ${event.systemId}, Check: ${event.checkId}`);
      console.log(`  Status: ${event.currentStatus}`);
      
      // Forward health check results to recovery orchestrator
      if (event.eventType === 'health_check_completed' && event.data) {
        const results = this.healthEngine.getAllResults();
        const checkResult = event.checkId ? results.get(event.checkId) : undefined;
        if (checkResult) {
          this.recoveryOrchestrator.processHealthCheckResult(checkResult);
        }
      }
    });
    
    // Listen for recovery events
    this.recoveryOrchestrator.onEvent((event) => {
      console.log(`[${event.timestamp.toISOString()}] Recovery Event: ${event.eventType}`);
      console.log(`  System: ${event.systemId}, Policy: ${event.policyId || 'none'}`);
      console.log(`  Message: ${event.data.message}`);
      
      if (event.result) {
        console.log(`  Result: ${event.result.success ? 'Success' : 'Failed'}`);
        if (event.result.details) {
          console.log(`  Details: ${JSON.stringify(event.result.details)}`);
        }
      }
    });
  }
  
  /**
   * Start the self-healing system
   */
  public start(): void {
    console.log('🚢 Starting Self-Healing System...');
    
    // Set initial operational context
    this.healthEngine.updateOperationalContext(OperationalContext.SAILING);
    this.recoveryOrchestrator.updateOperationalContext(OperationalContext.SAILING);
    
    // Set initial marine environment
    const environment: MarineEnvironmentStatus = {
      seaState: 'moderate',
      weather: 'clear',
      windSpeed: 12,
      temperature: 22,
      powerStatus: 'normal',
      connectivityQuality: 0.9,
      expectedFailureRate: 1.0,
      recommendedTimeoutMultiplier: 1.0,
      criticalOperationsOnly: false
    };
    
    this.healthEngine.updateMarineEnvironment(environment);
    this.recoveryOrchestrator.updateMarineEnvironment(environment);
    
    // Start the health check engine
    this.healthEngine.start();
    
    console.log('✅ Self-Healing System started');
  }
  
  /**
   * Stop the self-healing system
   */
  public stop(): void {
    console.log('🛑 Stopping Self-Healing System...');
    this.healthEngine.stop();
    console.log('✅ Self-Healing System stopped');
  }
  
  /**
   * Simulate GPS degradation
   */
  public simulateGPSDegradation(): void {
    console.log('🔄 Simulating GPS degradation...');
    
    // Degrade GPS state
    this.gpsState.satelliteCount = 3;
    this.gpsState.hdop = 4.5;
    this.gpsState.isCalibrated = false;
    
    console.log(`📉 GPS degraded: ${this.gpsState.satelliteCount} satellites, HDOP: ${this.gpsState.hdop}`);
  }
  
  /**
   * Simulate GPS failure
   */
  public simulateGPSFailure(): void {
    console.log('🔄 Simulating GPS failure...');
    
    // Fail GPS
    this.gpsState.satelliteCount = 0;
    this.gpsState.hdop = 10.0;
    this.gpsState.fix = '2d' as const; // Changed from 'none' to valid enum value
    this.gpsState.isCalibrated = false;
    
    console.log('📉 GPS failed: No satellite fix');
  }
  
  /**
   * Simulate GPS recovery
   */
  public simulateGPSRecovery(): void {
    console.log('🔄 Simulating GPS recovery...');
    
    // Recover GPS
    this.gpsState.satelliteCount = 9;
    this.gpsState.hdop = 1.0;
    this.gpsState.fix = '3d' as const;
    this.gpsState.isCalibrated = true;
    
    console.log(`📈 GPS recovered: ${this.gpsState.satelliteCount} satellites, HDOP: ${this.gpsState.hdop}`);
  }
  
  /**
   * Mock GPS data provider
   */
  private async mockGPSDataProvider(): Promise<GPSData> {
    return {
      latitude: 37.7749 + (Math.random() - 0.5) * 0.001,
      longitude: -122.4194 + (Math.random() - 0.5) * 0.001,
      altitude: 10 + Math.random() * 5,
      satelliteCount: this.gpsState.satelliteCount,
      hdop: this.gpsState.hdop,
      vdop: this.gpsState.hdop * 1.2,
      speed: Math.random() * 10,
      course: Math.random() * 360,
      timestamp: new Date(),
      fix: this.gpsState.fix
    };
  }
  
  /**
   * Utility function to wait
   */
  private wait(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

/**
 * Run the self-healing example
 */
export async function runSelfHealingExample(): Promise<void> {
  const example = new SelfHealingExample();
  
  try {
    // Start the self-healing system
    example.start();
    
    // Wait for initial health checks
    console.log('\n⏱️ Waiting for initial health checks...');
    await new Promise(resolve => setTimeout(resolve, 3000));
    
    // Simulate GPS degradation
    example.simulateGPSDegradation();
    console.log('\n⏱️ Waiting for health checks to detect degradation...');
    await new Promise(resolve => setTimeout(resolve, 5000));
    
    // Simulate GPS failure
    example.simulateGPSFailure();
    console.log('\n⏱️ Waiting for health checks to detect failure...');
    await new Promise(resolve => setTimeout(resolve, 5000));
    
    // Simulate GPS recovery
    example.simulateGPSRecovery();
    console.log('\n⏱️ Waiting for health checks to detect recovery...');
    await new Promise(resolve => setTimeout(resolve, 5000));
    
    // Keep running for a bit to see ongoing monitoring
    console.log('\n⏱️ Running continuous monitoring for 10 seconds...');
    await new Promise(resolve => setTimeout(resolve, 10000));
    
  } finally {
    // Clean shutdown
    example.stop();
  }
}

// Export for easy testing
export default SelfHealingExample;
