/**
 * Example usage of marine health monitoring system
 * This demonstrates how to set up and use health checks for a sailboat
 */

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

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

import { 
  BatteryHealthCheck, 
  createBatteryHealthCheck, 
  BatteryData 
} from '../marine/BatteryHealthCheck';

/**
 * Example marine health monitoring setup for a sailboat
 */
export class MarineHealthMonitoringExample {
  private healthEngine: HealthCheckEngine;
  private gpsHealthCheck!: GPSHealthCheck;
  private battery48vHealthCheck!: BatteryHealthCheck;
  private battery12vHealthCheck!: BatteryHealthCheck;

  constructor() {
    this.healthEngine = defaultHealthCheckEngine;
    
    // Set up event listening
    this.setupEventHandling();
    
    // Initialize health checks
    this.initializeHealthChecks();
  }

  /**
   * Initialize all marine health checks
   */
  private initializeHealthChecks(): void {
    // GPS Health Check
    this.gpsHealthCheck = createGPSHealthCheck(
      this.mockGPSDataProvider.bind(this),
      {
        // Custom configuration for this specific GPS unit
        interval: 15000, // Check every 15 seconds instead of default 10
        thresholds: {
          warning: 0.7,   // Slightly higher threshold for this critical system
          critical: 0.4,
          unit: 'health_score'
        }
      }
    );

    // 48V House Battery Health Check
    this.battery48vHealthCheck = createBatteryHealthCheck(
      this.mock48VBatteryDataProvider.bind(this),
      {
        checkId: 'house-battery-48v',
        name: '48V House Battery Health',
        interval: 20000, // Check every 20 seconds
        thresholds: {
          warning: 0.6,
          critical: 0.3,
          unit: 'health_score'
        }
      }
    );

    // 12V Service Battery Health Check
    this.battery12vHealthCheck = createBatteryHealthCheck(
      this.mock12VBatteryDataProvider.bind(this),
      {
        checkId: 'service-battery-12v',
        name: '12V Service Battery Health',
        interval: 30000, // Check every 30 seconds
        thresholds: {
          warning: 0.6,
          critical: 0.3,
          unit: 'health_score'
        }
      }
    );

    // Register all health checks with the engine
    this.healthEngine.registerHealthCheck(this.gpsHealthCheck);
    this.healthEngine.registerHealthCheck(this.battery48vHealthCheck);
    this.healthEngine.registerHealthCheck(this.battery12vHealthCheck);
  }

  /**
   * Set up event handling for health monitoring events
   */
  private setupEventHandling(): void {
    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}`);
      console.log(`  Message: ${event.data.message}`);
      
      if (event.data.score !== undefined) {
        console.log(`  Score: ${(event.data.score * 100).toFixed(1)}%`);
      }

      // Handle critical alerts
      if (event.eventType === 'alert_triggered' && event.currentStatus === HealthStatus.CRITICAL) {
        this.handleCriticalAlert(event);
      }

      // Handle system recovery
      if (event.eventType === 'system_recovery') {
        this.handleSystemRecovery(event);
      }
    });
  }

  /**
   * Handle critical health alerts
   */
  private handleCriticalAlert(event: HealthMonitoringEvent): void {
    console.error(`🚨 CRITICAL ALERT: ${event.data.message}`);
    
    // In a real implementation, this might:
    // - Send notifications to crew
    // - Log to emergency systems
    // - Trigger automatic responses
    // - Update navigation displays
    
    if (event.checkId === 'gps-health') {
      console.error('⚠️  GPS CRITICAL: Switch to backup navigation methods');
    } else if (event.checkId && event.checkId.includes('battery')) {
      console.error('⚠️  BATTERY CRITICAL: Implement power conservation measures');
    }
  }

  /**
   * Handle system recovery events
   */
  private handleSystemRecovery(event: HealthMonitoringEvent): void {
    console.log(`✅ System Recovery: ${event.data.message}`);
  }

  /**
   * Start the health monitoring system
   */
  public start(): void {
    console.log('🚢 Starting Marine Health Monitoring System...');
    
    // Set initial operational context
    this.healthEngine.updateOperationalContext(OperationalContext.DOCKED);
    
    // Set initial marine environment
    this.updateMarineEnvironment({
      seaState: 'calm',
      weather: 'clear',
      powerStatus: 'normal',
      criticalOperationsOnly: false
    });

    // Start the health check engine
    this.healthEngine.start();
    
    console.log('✅ Marine Health Monitoring System started');
  }

  /**
   * Stop the health monitoring system
   */
  public stop(): void {
    console.log('🛑 Stopping Marine Health Monitoring System...');
    this.healthEngine.stop();
    console.log('✅ Marine Health Monitoring System stopped');
  }

  /**
   * Update operational context (e.g., when leaving dock, anchoring, etc.)
   */
  public updateOperationalContext(context: OperationalContextType): void {
    console.log(`🔄 Updating operational context to: ${context}`);
    this.healthEngine.updateOperationalContext(context);
  }

  /**
   * Update marine environment conditions
   */
  public updateMarineEnvironment(environment: Partial<MarineEnvironmentStatus>): void {
    console.log('🌊 Updating marine environment conditions');
    
    // Get current environment and merge with updates
    const currentEnv: MarineEnvironmentStatus = {
      seaState: 'calm',
      weather: 'clear',
      windSpeed: 5,
      temperature: 22,
      powerStatus: 'normal',
      connectivityQuality: 0.9,
      expectedFailureRate: 1.0,
      recommendedTimeoutMultiplier: 1.0,
      criticalOperationsOnly: false,
      ...environment
    };
    
    this.healthEngine.updateMarineEnvironment(currentEnv);
  }

  /**
   * Get current health status summary
   */
  public async getHealthSummary(): Promise<void> {
    console.log('\n📊 Current Health Status Summary:');
    console.log('================================');
    
    const results = this.healthEngine.getAllResults();
    
    for (const [checkId, result] of results) {
      const statusIcon = this.getStatusIcon(result.status);
      const scorePercent = (result.score * 100).toFixed(1);
      
      console.log(`${statusIcon} ${result.name}: ${result.status} (${scorePercent}%)`);
      console.log(`   ${result.message}`);
      
      if (result.details) {
        const importantDetails = this.extractImportantDetails(result.details);
        if (importantDetails.length > 0) {
          console.log(`   Details: ${importantDetails.join(', ')}`);
        }
      }
      console.log('');
    }
  }

  /**
   * Simulate different sailing scenarios
   */
  public async simulateScenarios(): Promise<void> {
    console.log('\n🎭 Simulating different sailing scenarios...\n');

    // Scenario 1: Leaving dock
    console.log('📍 Scenario 1: Leaving dock');
    this.updateOperationalContext(OperationalContext.MOTORING);
    await this.wait(2000);
    await this.getHealthSummary();

    // Scenario 2: Sailing in good conditions
    console.log('📍 Scenario 2: Sailing in good conditions');
    this.updateOperationalContext(OperationalContext.SAILING);
    this.updateMarineEnvironment({
      seaState: 'moderate', // Valid enum value
      weather: 'clear'
    });
    await this.wait(2000);
    await this.getHealthSummary();

    // Scenario 3: Rough weather
    console.log('📍 Scenario 3: Rough weather conditions');
    this.updateMarineEnvironment({
      seaState: 'rough',
      weather: 'storm'
    });
    await this.wait(2000);
    await this.getHealthSummary();

    // Scenario 4: Power conservation mode
    console.log('📍 Scenario 4: Power conservation mode');
    this.updateMarineEnvironment({
      seaState: 'moderate',
      weather: 'cloudy', // Valid enum value
      powerStatus: 'conservation'
    });
    await this.wait(2000);
    await this.getHealthSummary();

    // Scenario 5: Emergency situation
    console.log('📍 Scenario 5: Emergency situation');
    this.updateOperationalContext(OperationalContext.EMERGENCY);
    this.updateMarineEnvironment({
      seaState: 'very_rough',
      weather: 'storm',
      powerStatus: 'critical',
      criticalOperationsOnly: true
    });
    await this.wait(2000);
    await this.getHealthSummary();
  }

  /**
   * Mock GPS data provider (in real implementation, this would read from actual GPS)
   */
  private async mockGPSDataProvider(): Promise<GPSData> {
    // Simulate some variability in GPS data
    const baseData = {
      latitude: 37.7749 + (Math.random() - 0.5) * 0.001,
      longitude: -122.4194 + (Math.random() - 0.5) * 0.001,
      altitude: 10 + Math.random() * 5,
      satelliteCount: 8 + Math.floor(Math.random() * 4),
      hdop: 1.0 + Math.random() * 2.0,
      vdop: 1.2 + Math.random() * 2.0,
      speed: Math.random() * 10,
      course: Math.random() * 360,
      timestamp: new Date(),
      fix: Math.random() > 0.1 ? '3d' as const : '2d' as const
    };

    return baseData;
  }

  /**
   * Mock 48V battery data provider
   */
  private async mock48VBatteryDataProvider(): Promise<BatteryData> {
    return {
      voltage: 50.4 + (Math.random() - 0.5) * 4.0,
      current: (Math.random() - 0.5) * 20,
      temperature: 25 + (Math.random() - 0.5) * 10,
      stateOfCharge: 60 + Math.random() * 35,
      capacity: 400 + (Math.random() - 0.5) * 50,
      nominalCapacity: 400,
      cycleCount: Math.floor(Math.random() * 500),
      timestamp: new Date(),
      batteryType: '48v'
    };
  }

  /**
   * Mock 12V battery data provider
   */
  private async mock12VBatteryDataProvider(): Promise<BatteryData> {
    return {
      voltage: 12.6 + (Math.random() - 0.5) * 1.0,
      current: (Math.random() - 0.5) * 10,
      temperature: 25 + (Math.random() - 0.5) * 8,
      stateOfCharge: 70 + Math.random() * 25,
      capacity: 100 + (Math.random() - 0.5) * 20,
      nominalCapacity: 100,
      cycleCount: Math.floor(Math.random() * 800),
      timestamp: new Date(),
      batteryType: '12v'
    };
  }

  /**
   * Get status icon for display
   */
  private getStatusIcon(status: HealthStatusType): string {
    switch (status) {
      case HealthStatus.HEALTHY:
        return '✅';
      case HealthStatus.DEGRADED:
        return '⚠️';
      case HealthStatus.UNHEALTHY:
        return '🔶';
      case HealthStatus.CRITICAL:
        return '🚨';
      default:
        return '❓';
    }
  }

  /**
   * Extract important details for summary display
   */
  private extractImportantDetails(details: Record<string, any>): string[] {
    const important: string[] = [];
    
    if (details['voltage'] !== undefined) {
      important.push(`${details['voltage'].toFixed(2)}V`);
    }
    if (details['stateOfCharge'] !== undefined) {
      important.push(`${details['stateOfCharge']}% SoC`);
    }
    if (details['satelliteCount'] !== undefined) {
      important.push(`${details['satelliteCount']} sats`);
    }
    if (details['hdop'] !== undefined) {
      important.push(`HDOP ${details['hdop'].toFixed(1)}`);
    }
    if (details['temperature'] !== undefined) {
      important.push(`${details['temperature']}°C`);
    }
    
    return important;
  }

  /**
   * Utility function to wait
   */
  private wait(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

/**
 * Example usage function
 */
export async function runMarineHealthMonitoringExample(): Promise<void> {
  const monitor = new MarineHealthMonitoringExample();
  
  try {
    // Start the monitoring system
    monitor.start();
    
    // Wait a bit for initial health checks
    await new Promise(resolve => setTimeout(resolve, 3000));
    
    // Get initial health summary
    await monitor.getHealthSummary();
    
    // Run scenario simulations
    await monitor.simulateScenarios();
    
    // Keep running for a bit to see ongoing monitoring
    console.log('\n⏱️  Running continuous monitoring for 30 seconds...');
    await new Promise(resolve => setTimeout(resolve, 30000));
    
    // Final health summary
    await monitor.getHealthSummary();
    
  } finally {
    // Clean shutdown
    monitor.stop();
  }
}

// Export for easy testing
export default MarineHealthMonitoringExample;
