/**
 * Alert Escalation Policy Service
 * Manages alert escalation policies and runbooks
 */

export interface EscalationStep {
  step: number;
  minutesAfterAlert: number;
  channels: ('slack' | 'pagerduty' | 'email')[];
  notifyUsers: string[]; // User IDs or email addresses
  message?: string;
}

export interface EscalationPolicy {
  id: string;
  name: string;
  description: string;
  alertTypes: string[]; // Which alert types trigger this policy
  steps: EscalationStep[];
  enabled: boolean;
  createdAt: Date;
  updatedAt: Date;
}

export interface Runbook {
  id: string;
  alertType: string;
  title: string;
  description: string;
  steps: string[]; // Numbered steps for resolution
  estimatedResolutionTime: number; // minutes
  tags: string[];
  enabled: boolean;
  createdAt: Date;
  updatedAt: Date;
}

export interface ActiveEscalation {
  id: string;
  alertId: string;
  policyId: string;
  alertType: string;
  startedAt: Date;
  currentStep: number;
  nextEscalationAt: Date;
  status: 'active' | 'resolved' | 'acknowledged';
}

class EscalationPolicyService {
  private policies: Map<string, EscalationPolicy> = new Map();
  private runbooks: Map<string, Runbook> = new Map();
  private activeEscalations: Map<string, ActiveEscalation> = new Map();

  constructor() {
    this.initializeDefaultPolicies();
    this.initializeDefaultRunbooks();
  }

  /**
   * Initialize default escalation policies
   */
  private initializeDefaultPolicies() {
    // Critical latency policy
    this.createPolicy({
      name: 'Critical Latency Escalation',
      description: 'Escalation policy for critical latency alerts',
      alertTypes: ['latency_critical'],
      steps: [
        {
          step: 1,
          minutesAfterAlert: 0,
          channels: ['slack', 'pagerduty'],
          notifyUsers: ['ops-team'],
          message: 'Critical latency detected. Ops team notified.',
        },
        {
          step: 2,
          minutesAfterAlert: 5,
          channels: ['slack', 'pagerduty', 'email'],
          notifyUsers: ['ops-lead', 'engineering-lead'],
          message: 'Escalating: Critical latency persists. Engineering lead notified.',
        },
        {
          step: 3,
          minutesAfterAlert: 15,
          channels: ['pagerduty', 'email'],
          notifyUsers: ['cto'],
          message: 'Critical escalation: CTO notified of persistent latency issue.',
        },
      ],
      enabled: true,
    });

    // Delivery failure policy
    this.createPolicy({
      name: 'Delivery Failure Escalation',
      description: 'Escalation policy for email/SMS delivery failures',
      alertTypes: ['delivery_failure'],
      steps: [
        {
          step: 1,
          minutesAfterAlert: 0,
          channels: ['slack'],
          notifyUsers: ['support-team'],
          message: 'Delivery failure detected. Support team notified.',
        },
        {
          step: 2,
          minutesAfterAlert: 10,
          channels: ['slack', 'email'],
          notifyUsers: ['support-lead', 'backend-team'],
          message: 'Escalating: Delivery failures continue. Backend team notified.',
        },
        {
          step: 3,
          minutesAfterAlert: 30,
          channels: ['pagerduty', 'email'],
          notifyUsers: ['engineering-lead'],
          message: 'Critical escalation: Engineering lead notified of persistent delivery issues.',
        },
      ],
      enabled: true,
    });

    // Forecast accuracy policy
    this.createPolicy({
      name: 'Forecast Accuracy Degradation',
      description: 'Escalation policy for forecast model accuracy issues',
      alertTypes: ['forecast_accuracy_degrading'],
      steps: [
        {
          step: 1,
          minutesAfterAlert: 0,
          channels: ['slack'],
          notifyUsers: ['analytics-team'],
          message: 'Forecast accuracy degrading. Analytics team notified.',
        },
        {
          step: 2,
          minutesAfterAlert: 20,
          channels: ['slack', 'email'],
          notifyUsers: ['analytics-lead', 'data-science-team'],
          message: 'Escalating: Model accuracy continues to degrade. Data science team notified.',
        },
      ],
      enabled: true,
    });
  }

  /**
   * Initialize default runbooks
   */
  private initializeDefaultRunbooks() {
    this.createRunbook({
      alertType: 'latency_critical',
      title: 'Critical Latency Response',
      description: 'Runbook for responding to critical WebSocket latency alerts',
      steps: [
        'Check WebSocket connection metrics in monitoring dashboard',
        'Verify server CPU and memory utilization',
        'Check network connectivity and bandwidth usage',
        'Review recent deployments or configuration changes',
        'Check for database query performance issues',
        'Restart affected service if necessary',
        'Monitor metrics for 5 minutes to confirm resolution',
        'Post-incident: Review logs and identify root cause',
      ],
      estimatedResolutionTime: 15,
      tags: ['latency', 'websocket', 'performance'],
    });

    this.createRunbook({
      alertType: 'delivery_failure',
      title: 'Email/SMS Delivery Failure Response',
      description: 'Runbook for responding to email and SMS delivery failures',
      steps: [
        'Check Brevo email service status',
        'Check Twilio SMS service status',
        'Verify API credentials are correct',
        'Check delivery queue for stuck messages',
        'Review error logs for specific failure reasons',
        'Test email/SMS delivery with test account',
        'If Brevo/Twilio issue: wait for service recovery',
        'If local issue: restart delivery service',
        'Monitor delivery metrics for recovery',
      ],
      estimatedResolutionTime: 20,
      tags: ['delivery', 'email', 'sms', 'integration'],
    });

    this.createRunbook({
      alertType: 'forecast_accuracy_degrading',
      title: 'Forecast Model Accuracy Degradation',
      description: 'Runbook for responding to forecast model accuracy issues',
      steps: [
        'Check forecast model performance metrics',
        'Review recent data quality issues',
        'Verify training data is current and complete',
        'Check for anomalies in historical data',
        'Review model predictions vs actual values',
        'Consider retraining model with recent data',
        'Check for external factors affecting predictions',
        'Adjust model parameters if necessary',
        'Monitor accuracy improvement after changes',
      ],
      estimatedResolutionTime: 30,
      tags: ['forecasting', 'ml', 'accuracy'],
    });
  }

  /**
   * Create escalation policy
   */
  createPolicy(policy: Omit<EscalationPolicy, 'id' | 'createdAt' | 'updatedAt'>): EscalationPolicy {
    const id = `policy-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const fullPolicy: EscalationPolicy = {
      ...policy,
      id,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.policies.set(id, fullPolicy);
    console.log(`[Escalation Policy] Policy created: ${policy.name}`);
    return fullPolicy;
  }

  /**
   * Get escalation policy
   */
  getPolicy(policyId: string): EscalationPolicy | undefined {
    return this.policies.get(policyId);
  }

  /**
   * Get policies for alert type
   */
  getPoliciesForAlertType(alertType: string): EscalationPolicy[] {
    return Array.from(this.policies.values()).filter(
      (p) => p.enabled && p.alertTypes.includes(alertType)
    );
  }

  /**
   * List all policies
   */
  listPolicies(): EscalationPolicy[] {
    return Array.from(this.policies.values());
  }

  /**
   * Update policy
   */
  updatePolicy(policyId: string, updates: Partial<EscalationPolicy>): EscalationPolicy | undefined {
    const policy = this.policies.get(policyId);
    if (!policy) return undefined;

    const updated: EscalationPolicy = {
      ...policy,
      ...updates,
      id: policy.id,
      createdAt: policy.createdAt,
      updatedAt: new Date(),
    };

    this.policies.set(policyId, updated);
    console.log(`[Escalation Policy] Policy updated: ${policy.name}`);
    return updated;
  }

  /**
   * Delete policy
   */
  deletePolicy(policyId: string): boolean {
    const deleted = this.policies.delete(policyId);
    if (deleted) {
      console.log(`[Escalation Policy] Policy deleted: ${policyId}`);
    }
    return deleted;
  }

  /**
   * Create runbook
   */
  createRunbook(runbook: Omit<Runbook, 'id' | 'createdAt' | 'updatedAt'>): Runbook {
    const id = `runbook-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const fullRunbook: Runbook = {
      ...runbook,
      id,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.runbooks.set(id, fullRunbook);
    console.log(`[Escalation Policy] Runbook created: ${runbook.title}`);
    return fullRunbook;
  }

  /**
   * Get runbook
   */
  getRunbook(runbookId: string): Runbook | undefined {
    return this.runbooks.get(runbookId);
  }

  /**
   * Get runbook for alert type
   */
  getRunbookForAlertType(alertType: string): Runbook | undefined {
    const runbooks = Array.from(this.runbooks.values()).filter(
      (r) => r.enabled && r.alertType === alertType
    );
    return runbooks.length > 0 ? runbooks[0] : undefined;
  }

  /**
   * List all runbooks
   */
  listRunbooks(): Runbook[] {
    return Array.from(this.runbooks.values());
  }

  /**
   * Update runbook
   */
  updateRunbook(runbookId: string, updates: Partial<Runbook>): Runbook | undefined {
    const runbook = this.runbooks.get(runbookId);
    if (!runbook) return undefined;

    const updated: Runbook = {
      ...runbook,
      ...updates,
      id: runbook.id,
      createdAt: runbook.createdAt,
      updatedAt: new Date(),
    };

    this.runbooks.set(runbookId, updated);
    console.log(`[Escalation Policy] Runbook updated: ${runbook.title}`);
    return updated;
  }

  /**
   * Delete runbook
   */
  deleteRunbook(runbookId: string): boolean {
    const deleted = this.runbooks.delete(runbookId);
    if (deleted) {
      console.log(`[Escalation Policy] Runbook deleted: ${runbookId}`);
    }
    return deleted;
  }

  /**
   * Start escalation for alert
   */
  startEscalation(alertId: string, alertType: string, policyId: string): ActiveEscalation | undefined {
    const policy = this.getPolicy(policyId);
    if (!policy || !policy.enabled) return undefined;

    const escalationId = `escalation-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const firstStep = policy.steps[0];
    const nextEscalationAt = new Date(Date.now() + firstStep.minutesAfterAlert * 60 * 1000);

    const escalation: ActiveEscalation = {
      id: escalationId,
      alertId,
      policyId,
      alertType,
      startedAt: new Date(),
      currentStep: 1,
      nextEscalationAt,
      status: 'active',
    };

    this.activeEscalations.set(escalationId, escalation);
    console.log(`[Escalation Policy] Escalation started for alert ${alertId}`);
    return escalation;
  }

  /**
   * Get active escalation
   */
  getActiveEscalation(escalationId: string): ActiveEscalation | undefined {
    return this.activeEscalations.get(escalationId);
  }

  /**
   * Get escalations for alert
   */
  getEscalationsForAlert(alertId: string): ActiveEscalation[] {
    return Array.from(this.activeEscalations.values()).filter((e) => e.alertId === alertId);
  }

  /**
   * Acknowledge escalation
   */
  acknowledgeEscalation(escalationId: string): ActiveEscalation | undefined {
    const escalation = this.activeEscalations.get(escalationId);
    if (!escalation) return undefined;

    escalation.status = 'acknowledged';
    console.log(`[Escalation Policy] Escalation acknowledged: ${escalationId}`);
    return escalation;
  }

  /**
   * Resolve escalation
   */
  resolveEscalation(escalationId: string): ActiveEscalation | undefined {
    const escalation = this.activeEscalations.get(escalationId);
    if (!escalation) return undefined;

    escalation.status = 'resolved';
    this.activeEscalations.delete(escalationId);
    console.log(`[Escalation Policy] Escalation resolved: ${escalationId}`);
    return escalation;
  }

  /**
   * Get escalations due for next step
   */
  getEscalationsDueForNextStep(): ActiveEscalation[] {
    const now = new Date();
    return Array.from(this.activeEscalations.values()).filter(
      (e) => e.status === 'active' && e.nextEscalationAt <= now
    );
  }

  /**
   * Execute next escalation step
   */
  executeNextStep(escalationId: string): { success: boolean; message: string } {
    const escalation = this.activeEscalations.get(escalationId);
    if (!escalation) {
      return { success: false, message: 'Escalation not found' };
    }

    const policy = this.getPolicy(escalation.policyId);
    if (!policy) {
      return { success: false, message: 'Policy not found' };
    }

    const nextStep = policy.steps[escalation.currentStep];
    if (!nextStep) {
      return { success: false, message: 'No more escalation steps' };
    }

    // Execute next step (in production, would send notifications)
    console.log(`[Escalation Policy] Executing step ${nextStep.step} for escalation ${escalationId}`);
    console.log(`  Channels: ${nextStep.channels.join(', ')}`);
    console.log(`  Notify: ${nextStep.notifyUsers.join(', ')}`);

    // Update escalation
    escalation.currentStep += 1;
    const nextNextStep = policy.steps[escalation.currentStep];
    if (nextNextStep) {
      escalation.nextEscalationAt = new Date(Date.now() + nextNextStep.minutesAfterAlert * 60 * 1000);
    } else {
      escalation.status = 'resolved';
    }

    return { success: true, message: `Step ${nextStep.step} executed successfully` };
  }

  /**
   * List active escalations
   */
  listActiveEscalations(): ActiveEscalation[] {
    return Array.from(this.activeEscalations.values()).filter((e) => e.status === 'active');
  }
}

export const escalationPolicyService = new EscalationPolicyService();
