/**
 * SLA Enforcement Library
 *
 * Defines and enforces SLAs at phase boundaries in the CFN Loop.
 * Tracks compliance metrics and enables graceful degradation on breach.
 *
 * Phase 6: Production Hardening (Task 6.1)
 */

export interface SLADefinition {
  name: string;
  targetMs: number;          // Target completion time
  warnMs: number;            // Warning threshold (typically 80% of target)
  maxRetries: number;        // Max retry attempts on failure
  gracefulDegradation: boolean;  // Continue with warning vs hard fail
}

export interface SLACheckResult {
  compliant: boolean;
  elapsed: number;
  target: number;
  percentOfTarget: number;
  breached: boolean;
  warning: boolean;
}

export interface SLAMetrics {
  totalChecks: number;
  compliant: number;
  warnings: number;
  breaches: number;
  complianceRate: number;
  averageLatency: number;
}

/**
 * SLA Definitions for CFN Loop Phases
 * Based on performance targets from implementation plan
 */
export const SLAs: Record<string, SLADefinition> = {
  phase1_ruvector_init: {
    name: "RuVector Initialization (Phase 1)",
    targetMs: 5000,           // <5s for connection setup
    warnMs: 4000,             // Warn at 80%
    maxRetries: 2,
    gracefulDegradation: false  // Critical path - must succeed
  },

  phase2_decomposition: {
    name: "Decomposition Swarm (Phase 2)",
    targetMs: 10000,          // <10s total (4 decomposers sequential)
    warnMs: 8000,             // Warn at 80%
    maxRetries: 2,
    gracefulDegradation: true   // Can proceed with partial analysis
  },

  phase2_individual_decomposer: {
    name: "Individual Decomposer (Phase 2)",
    targetMs: 2500,           // ~2.5s per decomposer (4 sequential = 10s)
    warnMs: 2000,             // Warn at 80%
    maxRetries: 1,
    gracefulDegradation: true
  },

  phase3_validation: {
    name: "Async Validation Orchestration (Phase 3)",
    targetMs: 30000,          // <30s total (5 validators parallel)
    warnMs: 24000,            // Warn at 80%
    maxRetries: 1,
    gracefulDegradation: true   // Can proceed with partial validation
  },

  phase3_individual_validator: {
    name: "Individual Validator (Phase 3)",
    targetMs: 30000,          // Max 30s (parallel execution)
    warnMs: 24000,            // Warn at 80%
    maxRetries: 1,
    gracefulDegradation: true
  },

  phase4_ruvector_capture: {
    name: "RuVector Learning Capture (Phase 4)",
    targetMs: 3000,           // <3s for embeddings + storage
    warnMs: 2400,             // Warn at 80%
    maxRetries: 2,
    gracefulDegradation: true   // Learning is optional
  },

  phase4_rag_search: {
    name: "RuVector RAG Search (Phase 4)",
    targetMs: 2000,           // <2s for similarity search
    warnMs: 1600,             // Warn at 80%
    maxRetries: 1,
    gracefulDegradation: true   // Can proceed without similar cases
  },

  phase5_troubleshooting: {
    name: "Troubleshooting Analysis (Phase 5)",
    targetMs: 5000,           // <5s per analysis
    warnMs: 4000,             // Warn at 80%
    maxRetries: 1,
    gracefulDegradation: true   // Can proceed without troubleshooting
  },

  total_loop: {
    name: "Total CFN Loop",
    targetMs: 150000,         // <150s typical (target: <3 min)
    warnMs: 120000,           // Warn at 80%
    maxRetries: 0,
    gracefulDegradation: false  // Don't retry entire loop
  }
};

/**
 * SLA Enforcement Class
 * Tracks metrics and performs compliance checks
 */
export class SLAEnforcer {
  private metrics: Map<string, SLAMetrics> = new Map();
  private latencies: Map<string, number[]> = new Map();

  constructor() {
    // Initialize metrics for all SLAs
    Object.keys(SLAs).forEach(key => {
      this.metrics.set(key, {
        totalChecks: 0,
        compliant: 0,
        warnings: 0,
        breaches: 0,
        complianceRate: 0,
        averageLatency: 0
      });
      this.latencies.set(key, []);
    });
  }

  /**
   * Check SLA compliance for a phase
   *
   * @param slaKey - SLA definition key
   * @param elapsedMs - Actual elapsed time in milliseconds
   * @returns SLA check result with compliance status
   */
  checkCompliance(slaKey: string, elapsedMs: number): SLACheckResult {
    const sla = SLAs[slaKey];
    if (!sla) {
      throw new Error(`Unknown SLA key: ${slaKey}`);
    }

    const percentOfTarget = (elapsedMs / sla.targetMs) * 100;
    const warning = elapsedMs >= sla.warnMs && elapsedMs < sla.targetMs;
    const breached = elapsedMs >= sla.targetMs;
    const compliant = !breached;

    // Update metrics
    const metrics = this.metrics.get(slaKey)!;
    metrics.totalChecks++;
    if (compliant) metrics.compliant++;
    if (warning) metrics.warnings++;
    if (breached) metrics.breaches++;
    metrics.complianceRate = (metrics.compliant / metrics.totalChecks) * 100;

    // Track latency
    const latencies = this.latencies.get(slaKey)!;
    latencies.push(elapsedMs);
    metrics.averageLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length;

    return {
      compliant,
      elapsed: elapsedMs,
      target: sla.targetMs,
      percentOfTarget,
      breached,
      warning
    };
  }

  /**
   * Get metrics for a specific SLA
   */
  getMetrics(slaKey: string): SLAMetrics | undefined {
    return this.metrics.get(slaKey);
  }

  /**
   * Get all metrics
   */
  getAllMetrics(): Map<string, SLAMetrics> {
    return new Map(this.metrics);
  }

  /**
   * Get SLA definition
   */
  getSLA(slaKey: string): SLADefinition | undefined {
    return SLAs[slaKey];
  }

  /**
   * Reset metrics (useful for testing)
   */
  resetMetrics(): void {
    this.metrics.forEach(m => {
      m.totalChecks = 0;
      m.compliant = 0;
      m.warnings = 0;
      m.breaches = 0;
      m.complianceRate = 0;
      m.averageLatency = 0;
    });
    this.latencies.forEach(l => l.length = 0);
  }

  /**
   * Format SLA check result for logging
   */
  formatCheckResult(slaKey: string, result: SLACheckResult): string {
    const sla = SLAs[slaKey];
    const status = result.compliant ? "✓ COMPLIANT" : "✗ BREACHED";
    const icon = result.breached ? "⚠️" : result.warning ? "⏱️" : "✅";

    return `${icon} ${sla.name}: ${result.elapsed}ms / ${result.target}ms (${result.percentOfTarget.toFixed(1)}%) - ${status}`;
  }

  /**
   * Get compliance summary for reporting
   */
  getComplianceSummary(): {
    overall: number;
    byPhase: Record<string, number>;
    totalChecks: number;
    totalBreaches: number;
  } {
    let totalChecks = 0;
    let totalCompliant = 0;
    let totalBreaches = 0;
    const byPhase: Record<string, number> = {};

    this.metrics.forEach((metrics, key) => {
      totalChecks += metrics.totalChecks;
      totalCompliant += metrics.compliant;
      totalBreaches += metrics.breaches;
      byPhase[key] = metrics.complianceRate;
    });

    return {
      overall: totalChecks > 0 ? (totalCompliant / totalChecks) * 100 : 100,
      byPhase,
      totalChecks,
      totalBreaches
    };
  }
}

/**
 * Global SLA enforcer instance
 * Shared across all CFN Loop executions
 */
export const slaEnforcer = new SLAEnforcer();

/**
 * Utility: Measure execution time and check SLA
 *
 * Usage:
 * const result = await measureSLA("phase2_decomposition", async () => {
 *   return await decomposer.run();
 * });
 */
export async function measureSLA<T>(
  slaKey: string,
  fn: () => Promise<T>
): Promise<{ result: T; slaCheck: SLACheckResult }> {
  const start = Date.now();
  const result = await fn();
  const elapsed = Date.now() - start;
  const slaCheck = slaEnforcer.checkCompliance(slaKey, elapsed);

  return { result, slaCheck };
}

/**
 * Utility: Time a function without SLA enforcement
 * (for phases not yet covered by SLAs)
 */
export async function timePhase<T>(
  phaseName: string,
  fn: () => Promise<T>
): Promise<{ result: T; elapsed: number }> {
  const start = Date.now();
  const result = await fn();
  const elapsed = Date.now() - start;

  return { result, elapsed };
}
