/**
 * Recovery action types and interfaces for self-healing mechanisms
 */

import {
  HealthStatus,
  HealthStatusType,
  OperationalContext,
  OperationalContextType,
  MarineSystemType,
  MarineSystemTypeType,
  MarineEnvironmentStatus,
  HealthCheckResult
} from '../types';

/**
 * Recovery action types
 */
export enum RecoveryActionType {
  /**
   * Restart a component or service
   */
  RESTART = 'restart',
  
  /**
   * Switch to a backup system
   */
  FAILOVER = 'failover',
  
  /**
   * Reset a component to default settings
   */
  RESET = 'reset',
  
  /**
   * Recalibrate a sensor or component
   */
  RECALIBRATE = 'recalibrate',
  
  /**
   * Adjust configuration parameters
   */
  ADJUST_CONFIG = 'adjust_config',
  
  /**
   * Reduce load on a system
   */
  REDUCE_LOAD = 'reduce_load',
  
  /**
   * Isolate a component from the system
   */
  ISOLATE = 'isolate',
  
  /**
   * Notify crew for manual intervention
   */
  NOTIFY = 'notify'
}

/**
 * Recovery action priority
 */
export enum RecoveryPriority {
  /**
   * Low priority, can be delayed
   */
  LOW = 'low',
  
  /**
   * Normal priority
   */
  NORMAL = 'normal',
  
  /**
   * High priority, execute soon
   */
  HIGH = 'high',
  
  /**
   * Critical priority, execute immediately
   */
  CRITICAL = 'critical'
}

/**
 * Recovery action status
 */
export enum RecoveryStatus {
  /**
   * Action is pending execution
   */
  PENDING = 'pending',
  
  /**
   * Action is currently executing
   */
  EXECUTING = 'executing',
  
  /**
   * Action completed successfully
   */
  SUCCEEDED = 'succeeded',
  
  /**
   * Action failed
   */
  FAILED = 'failed',
  
  /**
   * Action was cancelled
   */
  CANCELLED = 'cancelled',
  
  /**
   * Action timed out
   */
  TIMEOUT = 'timeout'
}

/**
 * Recovery action configuration
 */
export interface RecoveryActionConfig {
  /**
   * Unique ID for this recovery action
   */
  actionId: string;
  
  /**
   * Human-readable name
   */
  name: string;
  
  /**
   * Type of recovery action
   */
  type: RecoveryActionType;
  
  /**
   * System type this action applies to
   */
  marineSystemType: MarineSystemTypeType;
  
  /**
   * Priority of this action
   */
  priority: RecoveryPriority;
  
  /**
   * Maximum execution time in ms
   */
  timeout: number;
  
  /**
   * Maximum number of retry attempts
   */
  maxRetries: number;
  
  /**
   * Delay between retries in ms
   */
  retryDelay: number;
  
  /**
   * Whether this action requires manual approval
   */
  requiresApproval: boolean;
  
  /**
   * Whether this action can run in automated mode
   */
  automatedExecution: boolean;
  
  /**
   * Marine-specific settings
   */
  marineSettings: {
    /**
     * Operational contexts where this action is allowed
     */
    allowedContexts: OperationalContextType[];
    
    /**
     * Whether this action is allowed in rough sea conditions
     */
    allowInRoughSeas: boolean;
    
    /**
     * Whether this action is power-aware
     */
    powerAware: boolean;
    
    /**
     * Whether this action affects vessel safety
     */
    safetyImpact: boolean;
    
    /**
     * Estimated power consumption in watts
     */
    powerConsumption: number;
  };
  
  /**
   * Action-specific parameters
   */
  parameters: Record<string, any>;
}

/**
 * Recovery action result
 */
export interface RecoveryActionResult {
  /**
   * Action ID
   */
  actionId: string;
  
  /**
   * Action name
   */
  name: string;
  
  /**
   * Action type
   */
  type: RecoveryActionType;
  
  /**
   * Execution status
   */
  status: RecoveryStatus;
  
  /**
   * Result message
   */
  message: string;
  
  /**
   * Start time
   */
  startTime: Date;
  
  /**
   * End time
   */
  endTime: Date;
  
  /**
   * Execution duration in ms
   */
  duration: number;
  
  /**
   * Number of retry attempts
   */
  retryCount: number;
  
  /**
   * Whether the action was successful
   */
  success: boolean;
  
  /**
   * Error details if failed
   */
  error?: string;
  
  /**
   * Action-specific result details
   */
  details?: Record<string, any>;
  
  /**
   * Marine context during execution
   */
  marineContext: {
    operationalContext: OperationalContextType;
    environmentalConditions?: Partial<MarineEnvironmentStatus> | undefined;
  };
  
  /**
   * Health check that triggered this action
   */
  triggeringCheck?: {
    checkId: string;
    status: HealthStatusType;
    score: number;
  } | undefined;
  
  /**
   * Health check result after recovery attempt
   */
  resultingCheck?: {
    checkId: string;
    status: HealthStatusType;
    score: number;
  };
}

/**
 * Recovery policy
 */
export interface RecoveryPolicy {
  /**
   * Policy ID
   */
  policyId: string;
  
  /**
   * Human-readable name
   */
  name: string;
  
  /**
   * Health check ID this policy applies to
   */
  checkId: string;
  
  /**
   * Marine system type
   */
  marineSystemType: MarineSystemTypeType;
  
  /**
   * Health status threshold to trigger recovery
   */
  triggerStatus: HealthStatusType;
  
  /**
   * Health score threshold to trigger recovery
   */
  triggerScore: number;
  
  /**
   * Number of consecutive failures before triggering
   */
  consecutiveFailures: number;
  
  /**
   * Recovery actions to attempt, in order
   */
  actions: string[];
  
  /**
   * Whether to stop after first successful action
   */
  stopOnSuccess: boolean;
  
  /**
   * Whether this policy is enabled
   */
  enabled: boolean;
  
  /**
   * Cooldown period between recovery attempts in ms
   */
  cooldownPeriod: number;
  
  /**
   * Maximum number of recovery attempts in a time window
   */
  maxAttempts: number;
  
  /**
   * Time window for max attempts in ms
   */
  attemptWindow: number;
  
  /**
   * Marine-specific settings
   */
  marineSettings: {
    /**
     * Operational contexts where this policy is active
     */
    activeContexts: OperationalContextType[];
    
    /**
     * Whether to apply in rough sea conditions
     */
    activeInRoughSeas: boolean;
    
    /**
     * Whether this policy is power-aware
     */
    powerAware: boolean;
    
    /**
     * Whether this policy affects vessel safety
     */
    safetyImpact: boolean;
  };
}

/**
 * Recovery event
 */
export interface RecoveryEvent {
  /**
   * Event ID
   */
  eventId: string;
  
  /**
   * Timestamp
   */
  timestamp: Date;
  
  /**
   * Event type
   */
  eventType: 'recovery_started' | 'recovery_completed' | 'recovery_failed' | 'policy_triggered' | 'action_executed';
  
  /**
   * System ID
   */
  systemId: string;
  
  /**
   * Check ID that triggered recovery
   */
  checkId?: string;
  
  /**
   * Policy ID
   */
  policyId?: string;
  
  /**
   * Action ID
   */
  actionId?: string;
  
  /**
   * Event data
   */
  data: {
    message: string;
    details?: Record<string, any> | undefined;
    marineContext: {
      operationalContext: OperationalContextType;
      environmentalConditions?: Partial<MarineEnvironmentStatus> | undefined;
    };
  };
  
  /**
   * Recovery result
   */
  result?: RecoveryActionResult;
}

/**
 * Abstract base class for recovery actions
 */
export abstract class BaseRecoveryAction {
  protected config: RecoveryActionConfig;
  protected lastResult?: RecoveryActionResult;
  protected retryCount = 0;
  
  constructor(config: RecoveryActionConfig) {
    this.config = config;
  }
  
  /**
   * Execute the recovery action
   */
  async execute(
    triggeringCheck: HealthCheckResult,
    operationalContext: OperationalContextType,
    marineEnvironment?: MarineEnvironmentStatus
  ): Promise<RecoveryActionResult> {
    const startTime = new Date();
    
    try {
      // Check if action is allowed in current context
      if (!this.isAllowedInContext(operationalContext, marineEnvironment)) {
        return this.createFailedResult(
          startTime,
          new Date(),
          'Action not allowed in current operational context',
          operationalContext,
          marineEnvironment,
          triggeringCheck
        );
      }
      
      // Execute the actual recovery action
      const result = await this.performRecovery(triggeringCheck, operationalContext, marineEnvironment);
      const endTime = new Date();
      
      if (result.success) {
        this.retryCount = 0;
        this.lastResult = result;
        return {
          ...result,
          startTime,
          endTime,
          duration: endTime.getTime() - startTime.getTime(),
          retryCount: this.retryCount,
          triggeringCheck: {
            checkId: triggeringCheck.checkId,
            status: triggeringCheck.status,
            score: triggeringCheck.score
          }
        };
      } else {
        // Handle retry logic
        if (this.retryCount < this.config.maxRetries) {
          this.retryCount++;
          await new Promise(resolve => setTimeout(resolve, this.config.retryDelay));
          return this.execute(triggeringCheck, operationalContext, marineEnvironment);
        } else {
          // Max retries reached
          const failedResult = this.createFailedResult(
            startTime,
            new Date(),
            `Recovery action failed after ${this.retryCount} retries: ${result.message}`,
            operationalContext,
            marineEnvironment,
            triggeringCheck
          );
          this.lastResult = failedResult;
          return failedResult;
        }
      }
    } catch (error) {
      const failedResult = this.createFailedResult(
        startTime,
        new Date(),
        `Recovery action error: ${(error as Error).message}`,
        operationalContext,
        marineEnvironment,
        triggeringCheck
      );
      this.lastResult = failedResult;
      return failedResult;
    }
  }
  
  /**
   * Get the last execution result
   */
  getLastResult(): RecoveryActionResult | undefined {
    return this.lastResult;
  }
  
  /**
   * Get action configuration
   */
  getConfig(): RecoveryActionConfig {
    return { ...this.config };
  }
  
  /**
   * Check if action is allowed in current context
   */
  protected isAllowedInContext(
    operationalContext: OperationalContextType,
    marineEnvironment?: MarineEnvironmentStatus
  ): boolean {
    // Check operational context
    if (!this.config.marineSettings.allowedContexts.includes(operationalContext)) {
      return false;
    }
    
    // Check sea conditions
    if (marineEnvironment?.seaState === 'rough' || marineEnvironment?.seaState === 'very_rough') {
      if (!this.config.marineSettings.allowInRoughSeas) {
        return false;
      }
    }
    
    // Check power status
    if (this.config.marineSettings.powerAware && marineEnvironment?.powerStatus === 'critical') {
      // Only allow safety-critical actions when power is critical
      return this.config.marineSettings.safetyImpact;
    }
    
    return true;
  }
  
  /**
   * Create a failed result
   */
  protected createFailedResult(
    startTime: Date,
    endTime: Date,
    message: string,
    operationalContext: OperationalContextType,
    marineEnvironment?: MarineEnvironmentStatus,
    triggeringCheck?: HealthCheckResult
  ): RecoveryActionResult {
    return {
      actionId: this.config.actionId,
      name: this.config.name,
      type: this.config.type,
      status: RecoveryStatus.FAILED,
      message,
      startTime,
      endTime,
      duration: endTime.getTime() - startTime.getTime(),
      retryCount: this.retryCount,
      success: false,
      error: message,
      marineContext: {
        operationalContext,
        environmentalConditions: marineEnvironment ? { ...marineEnvironment } : undefined
      },
      triggeringCheck: triggeringCheck ? {
        checkId: triggeringCheck.checkId,
        status: triggeringCheck.status,
        score: triggeringCheck.score
      } : undefined
    };
  }
  
  /**
   * Abstract method to perform the actual recovery action
   */
  protected abstract performRecovery(
    triggeringCheck: HealthCheckResult,
    operationalContext: OperationalContextType,
    marineEnvironment?: MarineEnvironmentStatus
  ): Promise<RecoveryActionResult>;
}
