/**
 * Battery Health Check for marine power systems
 */

import {
  BaseHealthCheck,
  HealthCheckResult,
  HealthCheckConfig,
  HealthCheckType,
  HealthStatus,
  HealthStatusType,
  OperationalContext,
  OperationalContextType,
  MarineSystemType,
  MarineSystemTypeType,
  MarineEnvironmentStatus
} from '../index';

/**
 * Battery data interface for health checking
 */
export interface BatteryData {
  voltage: number;           // Battery voltage in volts
  current: number;           // Current in/out in amps (positive = charging, negative = discharging)
  temperature: number;       // Battery temperature in Celsius
  stateOfCharge: number;     // State of charge percentage (0-100)
  capacity: number;          // Current capacity in Ah
  nominalCapacity: number;   // Nominal capacity in Ah
  cycleCount: number;        // Number of charge/discharge cycles
  timeToEmpty?: number;      // Estimated time to empty in minutes (when discharging)
  timeToFull?: number;       // Estimated time to full in minutes (when charging)
  timestamp: Date;
  batteryType: '12v' | '48v' | 'lithium' | 'agm' | 'gel';
}

/**
 * Battery Health Check implementation
 */
export class BatteryHealthCheck extends BaseHealthCheck {
  private batteryDataProvider: () => Promise<BatteryData>;
  private voltageHistory: { voltage: number; timestamp: Date }[] = [];
  private maxHistoryLength = 100;

  constructor(
    config: HealthCheckConfig,
    batteryDataProvider: () => Promise<BatteryData>
  ) {
    super(config);
    this.batteryDataProvider = batteryDataProvider;
  }

  protected async performCheck(
    operationalContext: OperationalContextType,
    marineEnvironment?: MarineEnvironmentStatus
  ): Promise<HealthCheckResult> {
    try {
      const batteryData = await this.batteryDataProvider();
      
      // Calculate health score based on multiple factors
      let score = 1.0;
      let status: HealthStatusType = HealthStatus.HEALTHY;
      const issues: string[] = [];
      const details: Record<string, any> = {
        voltage: batteryData.voltage,
        current: batteryData.current,
        temperature: batteryData.temperature,
        stateOfCharge: batteryData.stateOfCharge,
        capacity: batteryData.capacity,
        nominalCapacity: batteryData.nominalCapacity,
        capacityHealth: (batteryData.capacity / batteryData.nominalCapacity) * 100,
        cycleCount: batteryData.cycleCount,
        batteryType: batteryData.batteryType
      };

      // Get voltage thresholds based on battery type
      const voltageThresholds = this.getVoltageThresholds(batteryData.batteryType);

      // Check voltage levels
      if (batteryData.voltage < voltageThresholds.critical) {
        score = 0.0;
        status = HealthStatus.CRITICAL;
        issues.push(`Critical low voltage: ${batteryData.voltage.toFixed(2)}V`);
      } else if (batteryData.voltage < voltageThresholds.warning) {
        score -= 0.4;
        issues.push(`Low voltage: ${batteryData.voltage.toFixed(2)}V`);
      } else if (batteryData.voltage > voltageThresholds.overcharge) {
        score -= 0.3;
        issues.push(`High voltage: ${batteryData.voltage.toFixed(2)}V`);
      }

      // Check state of charge
      if (batteryData.stateOfCharge < 20) {
        score -= 0.3;
        issues.push(`Low state of charge: ${batteryData.stateOfCharge}%`);
      } else if (batteryData.stateOfCharge < 30) {
        score -= 0.1;
        issues.push(`Marginal state of charge: ${batteryData.stateOfCharge}%`);
      }

      // Check battery capacity health
      const capacityHealth = (batteryData.capacity / batteryData.nominalCapacity) * 100;
      if (capacityHealth < 60) {
        score -= 0.4;
        issues.push(`Poor capacity health: ${capacityHealth.toFixed(1)}%`);
      } else if (capacityHealth < 80) {
        score -= 0.2;
        issues.push(`Reduced capacity: ${capacityHealth.toFixed(1)}%`);
      }

      // Check temperature
      const tempThresholds = this.getTemperatureThresholds(batteryData.batteryType);
      if (batteryData.temperature < tempThresholds.coldCritical || 
          batteryData.temperature > tempThresholds.hotCritical) {
        score -= 0.5;
        issues.push(`Critical temperature: ${batteryData.temperature}°C`);
      } else if (batteryData.temperature < tempThresholds.coldWarning || 
                 batteryData.temperature > tempThresholds.hotWarning) {
        score -= 0.2;
        issues.push(`Temperature concern: ${batteryData.temperature}°C`);
      }

      // Check for excessive current draw
      if (Math.abs(batteryData.current) > batteryData.nominalCapacity * 0.5) {
        score -= 0.2;
        const direction = batteryData.current > 0 ? 'charging' : 'discharging';
        issues.push(`High current ${direction}: ${Math.abs(batteryData.current).toFixed(1)}A`);
      }

      // Check cycle count (if available)
      if (batteryData.cycleCount > 0) {
        const expectedLifeCycles = this.getExpectedLifeCycles(batteryData.batteryType);
        const cycleHealth = Math.max(0, 1 - (batteryData.cycleCount / expectedLifeCycles));
        score = Math.min(score, score * (0.7 + 0.3 * cycleHealth));
        
        if (batteryData.cycleCount > expectedLifeCycles * 0.8) {
          issues.push(`High cycle count: ${batteryData.cycleCount}`);
        }
      }

      // Add voltage to history and check for voltage drop trends
      this.voltageHistory.push({
        voltage: batteryData.voltage,
        timestamp: batteryData.timestamp
      });

      // Keep history manageable
      if (this.voltageHistory.length > this.maxHistoryLength) {
        this.voltageHistory = this.voltageHistory.slice(-this.maxHistoryLength);
      }

      // Check for voltage drop trend (if we have enough history)
      if (this.voltageHistory.length >= 10) {
        const recentVoltages = this.voltageHistory.slice(-10);
        const voltageDropRate = this.calculateVoltageDropRate(recentVoltages);
        
        if (voltageDropRate > 0.1) { // More than 0.1V drop per hour
          score -= 0.2;
          issues.push(`Rapid voltage drop detected: ${voltageDropRate.toFixed(3)}V/hr`);
          details['voltageDropRate'] = voltageDropRate;
        }
      }

      // Environmental adjustments
      if (marineEnvironment) {
        if (marineEnvironment.powerStatus === 'critical') {
          // In critical power situations, battery health is even more important
          score = Math.min(score, score * 0.9);
          details['criticalPowerMode'] = true;
        }

        if (marineEnvironment.seaState === 'very_rough') {
          // Rough seas can affect battery performance
          score = Math.max(score - 0.05, 0);
          details['roughSeaImpact'] = true;
        }
      }

      // Operational context adjustments
      if (operationalContext === OperationalContext.EMERGENCY) {
        // In emergency situations, battery reliability is critical
        if (score < 0.7) {
          score = Math.min(score, 0.5);
        }
      }

      // Determine final status
      score = Math.max(0, Math.min(1, score));
      if (score >= 0.8) {
        status = HealthStatus.HEALTHY;
      } else if (score >= 0.6) {
        status = HealthStatus.DEGRADED;
      } else if (score >= 0.3) {
        status = HealthStatus.UNHEALTHY;
      } else {
        status = HealthStatus.CRITICAL;
      }

      const message = issues.length > 0 
        ? `Battery issues detected: ${issues.join(', ')}`
        : 'Battery operating normally';

      return {
        checkId: this.config.checkId,
        name: this.config.name,
        type: this.config.type,
        marineSystemType: this.config.marineSystemType,
        status,
        score,
        message,
        details,
        timestamp: new Date(),
        executionTime: 0, // Will be set by base class
        marineContext: {
          operationalContext,
          environmentalImpact: marineEnvironment?.seaState === 'very_rough',
          safetyImpact: true, // Battery is critical for all systems
          powerImpact: 0 // Battery monitoring uses minimal power
        },
        thresholds: this.config.thresholds
      };

    } catch (error) {
      throw new Error(`Battery health check failed: ${(error as Error).message}`);
    }
  }

  /**
   * Get voltage thresholds based on battery type
   */
  private getVoltageThresholds(batteryType: string) {
    switch (batteryType) {
      case '12v':
        return {
          critical: 11.8,
          warning: 12.2,
          normal: 12.6,
          overcharge: 14.8
        };
      case '48v':
        return {
          critical: 47.2,
          warning: 48.8,
          normal: 50.4,
          overcharge: 59.2
        };
      case 'lithium':
        return {
          critical: 11.0,
          warning: 12.0,
          normal: 13.0,
          overcharge: 14.6
        };
      default:
        return {
          critical: 11.8,
          warning: 12.2,
          normal: 12.6,
          overcharge: 14.8
        };
    }
  }

  /**
   * Get temperature thresholds based on battery type
   */
  private getTemperatureThresholds(batteryType: string) {
    switch (batteryType) {
      case 'lithium':
        return {
          coldCritical: -10,
          coldWarning: 0,
          hotWarning: 45,
          hotCritical: 60
        };
      case 'agm':
      case 'gel':
        return {
          coldCritical: -20,
          coldWarning: -10,
          hotWarning: 50,
          hotCritical: 65
        };
      default:
        return {
          coldCritical: -15,
          coldWarning: -5,
          hotWarning: 50,
          hotCritical: 60
        };
    }
  }

  /**
   * Get expected life cycles based on battery type
   */
  private getExpectedLifeCycles(batteryType: string): number {
    switch (batteryType) {
      case 'lithium':
        return 3000;
      case 'agm':
        return 1000;
      case 'gel':
        return 1200;
      default:
        return 800;
    }
  }

  /**
   * Calculate voltage drop rate from recent history
   */
  private calculateVoltageDropRate(voltageHistory: { voltage: number; timestamp: Date }[]): number {
    if (voltageHistory.length < 2) return 0;

    const first = voltageHistory[0];
    const last = voltageHistory[voltageHistory.length - 1];
    
    if (!first || !last) return 0;
    
    const voltageDrop = first.voltage - last.voltage;
    const timeDiffHours = (last.timestamp.getTime() - first.timestamp.getTime()) / (1000 * 60 * 60);
    
    return timeDiffHours > 0 ? voltageDrop / timeDiffHours : 0;
  }
}

/**
 * Factory function to create battery health check with standard marine configuration
 */
export function createBatteryHealthCheck(
  batteryDataProvider: () => Promise<BatteryData>,
  customConfig?: Partial<HealthCheckConfig>
): BatteryHealthCheck {
  const defaultConfig: HealthCheckConfig = {
    checkId: 'battery-health',
    name: 'Battery System Health',
    type: HealthCheckType.POWER,
    marineSystemType: MarineSystemType.POWER as MarineSystemTypeType,
    interval: 30000, // Check every 30 seconds
    timeout: 5000,   // 5 second timeout
    retryCount: 2,
    thresholds: {
      warning: 0.6,
      critical: 0.3,
      unit: 'health_score'
    },
    marineSettings: {
      operationalContexts: [
        OperationalContext.SAILING,
        OperationalContext.MOTORING,
        OperationalContext.ANCHORED,
        OperationalContext.DOCKED,
        OperationalContext.EMERGENCY
      ] as OperationalContextType[],
      environmentalSensitivity: 0.2, // Somewhat sensitive to environmental conditions
      powerAware: false, // Battery monitoring is always critical
      safetyImpact: true
    },
    advanced: {
      trendAnalysis: true,
      predictiveAlerts: true,
      adaptiveThresholds: true,
      historicalComparison: true
    },
    ...customConfig
  };

  return new BatteryHealthCheck(defaultConfig, batteryDataProvider);
}
