/**
 * Regression Detection & Auto-Escalation
 *
 * If quality scores drop, auto-escalate review frequency.
 * Monitors for:
 * - Score drops per dimension
 * - Approval rate drops
 * - Calibration drift (predictions becoming inaccurate)
 * - New rejection patterns emerging
 */

import type {
  EnrichedFeedbackEvent,
  Anomaly,
  QualityDimension,
  AutonomyTier,
} from "../types.js";
import {
  getAutonomyLevel,
  recordReviewOutcome,
  loadAutonomyLevels,
} from "./diminishing-review.js";

// ═══════════════════════════════════════════════════════════════
// REGRESSION TYPES
// ═══════════════════════════════════════════════════════════════

export interface RegressionReport {
  /** Whether any regression was detected */
  hasRegression: boolean;
  /** Detected regressions */
  regressions: RegressionDetail[];
  /** Recommended actions */
  actions: RegressionAction[];
  /** Severity of the worst regression */
  worstSeverity: "none" | "minor" | "moderate" | "severe";
}

export interface RegressionDetail {
  type:
    | "approval_rate"
    | "dimension_score"
    | "calibration_drift"
    | "new_rejection_pattern";
  description: string;
  severity: "minor" | "moderate" | "severe";
  data: {
    before: number;
    after: number;
    delta: number;
    dimension?: QualityDimension;
    taskType?: string;
  };
}

export interface RegressionAction {
  action:
    | "escalate_review" // Increase HITL frequency
    | "demote_tier" // Reduce autonomy level
    | "recalibrate" // Force recalibration
    | "alert" // Send alert to operator
    | "pause_auto_approve"; // Temporarily pause all auto-approvals
  reason: string;
  urgency: "low" | "medium" | "high";
  affectedTaskTypes?: string[];
}

// ═══════════════════════════════════════════════════════════════
// REGRESSION DETECTION
// ═══════════════════════════════════════════════════════════════

/**
 * Run comprehensive regression detection on recent feedback.
 *
 * Compares two windows of feedback:
 * - "before" window: events from daysBack to daysBack/2
 * - "after" window: events from daysBack/2 to now
 */
export function detectRegression(
  events: EnrichedFeedbackEvent[],
  windowDays: number = 14
): RegressionReport {
  if (events.length < 10) {
    return {
      hasRegression: false,
      regressions: [],
      actions: [],
      worstSeverity: "none",
    };
  }

  const now = Date.now();
  const midpoint = now - (windowDays / 2) * 24 * 60 * 60 * 1000;
  const start = now - windowDays * 24 * 60 * 60 * 1000;

  const beforeWindow = events.filter((e) => {
    const t = new Date(e.timestamp).getTime();
    return t >= start && t < midpoint;
  });

  const afterWindow = events.filter((e) => {
    const t = new Date(e.timestamp).getTime();
    return t >= midpoint && t <= now;
  });

  if (beforeWindow.length < 3 || afterWindow.length < 3) {
    return {
      hasRegression: false,
      regressions: [],
      actions: [],
      worstSeverity: "none",
    };
  }

  const regressions: RegressionDetail[] = [];

  // 1. Check approval rate regression
  const beforeApprovalRate = computeRate(beforeWindow, "approved");
  const afterApprovalRate = computeRate(afterWindow, "approved");
  const approvalDelta = afterApprovalRate - beforeApprovalRate;

  if (approvalDelta < -0.1) {
    // >10% drop
    regressions.push({
      type: "approval_rate",
      description: `Approval rate dropped from ${pct(beforeApprovalRate)} to ${pct(afterApprovalRate)} (${pct(approvalDelta)} change)`,
      severity: approvalDelta < -0.2 ? "severe" : "moderate",
      data: {
        before: beforeApprovalRate,
        after: afterApprovalRate,
        delta: approvalDelta,
      },
    });
  }

  // 2. Check per-dimension score regression
  const dimensionRegressions = checkDimensionRegression(
    beforeWindow,
    afterWindow
  );
  regressions.push(...dimensionRegressions);

  // 3. Check calibration drift
  const calibrationDrift = checkCalibrationDrift(beforeWindow, afterWindow);
  if (calibrationDrift) {
    regressions.push(calibrationDrift);
  }

  // Generate actions
  const actions = generateActions(regressions);

  // Determine worst severity
  let worstSeverity: "none" | "minor" | "moderate" | "severe" = "none";
  for (const r of regressions) {
    if (r.severity === "severe") worstSeverity = "severe";
    else if (r.severity === "moderate" && worstSeverity !== "severe")
      worstSeverity = "moderate";
    else if (r.severity === "minor" && worstSeverity === "none")
      worstSeverity = "minor";
  }

  return {
    hasRegression: regressions.length > 0,
    regressions,
    actions,
    worstSeverity,
  };
}

// ═══════════════════════════════════════════════════════════════
// DIMENSION REGRESSION
// ═══════════════════════════════════════════════════════════════

function checkDimensionRegression(
  before: EnrichedFeedbackEvent[],
  after: EnrichedFeedbackEvent[]
): RegressionDetail[] {
  const regressions: RegressionDetail[] = [];

  const beforeScores = aggregateDimensionScores(before);
  const afterScores = aggregateDimensionScores(after);

  for (const [dim, beforeAvg] of Object.entries(beforeScores)) {
    const afterAvg = afterScores[dim];
    if (afterAvg === undefined) continue;

    const delta = afterAvg - beforeAvg;
    if (delta < -1.0) {
      // >1 point drop
      regressions.push({
        type: "dimension_score",
        description: `${dim} score dropped from ${beforeAvg.toFixed(1)} to ${afterAvg.toFixed(1)}`,
        severity: delta < -2.0 ? "severe" : "moderate",
        data: {
          before: beforeAvg,
          after: afterAvg,
          delta,
          dimension: dim as QualityDimension,
        },
      });
    }
  }

  return regressions;
}

function aggregateDimensionScores(
  events: EnrichedFeedbackEvent[]
): Record<string, number> {
  const scores: Record<string, number[]> = {};

  for (const event of events) {
    for (const score of event.feedback.scores ?? []) {
      if (!scores[score.dimension]) {
        scores[score.dimension] = [];
      }
      scores[score.dimension]!.push(score.score);
    }
  }

  const result: Record<string, number> = {};
  for (const [dim, values] of Object.entries(scores)) {
    result[dim] = values.reduce((a, b) => a + b, 0) / values.length;
  }
  return result;
}

// ═══════════════════════════════════════════════════════════════
// CALIBRATION DRIFT
// ═══════════════════════════════════════════════════════════════

function checkCalibrationDrift(
  before: EnrichedFeedbackEvent[],
  after: EnrichedFeedbackEvent[]
): RegressionDetail | null {
  const beforeDeltas = extractPredictionDeltas(before);
  const afterDeltas = extractPredictionDeltas(after);

  if (beforeDeltas.length < 3 || afterDeltas.length < 3) return null;

  const beforeAvgDelta =
    beforeDeltas.reduce((a, b) => a + Math.abs(b), 0) / beforeDeltas.length;
  const afterAvgDelta =
    afterDeltas.reduce((a, b) => a + Math.abs(b), 0) / afterDeltas.length;

  const driftDelta = afterAvgDelta - beforeAvgDelta;

  if (driftDelta > 0.5) {
    return {
      type: "calibration_drift",
      description: `Prediction accuracy degraded: avg error ${beforeAvgDelta.toFixed(1)} → ${afterAvgDelta.toFixed(1)}`,
      severity: driftDelta > 1.0 ? "severe" : "moderate",
      data: {
        before: beforeAvgDelta,
        after: afterAvgDelta,
        delta: driftDelta,
      },
    };
  }

  return null;
}

function extractPredictionDeltas(
  events: EnrichedFeedbackEvent[]
): number[] {
  return events
    .filter((e) => e._predictionDelta !== undefined)
    .map((e) => e._predictionDelta!);
}

// ═══════════════════════════════════════════════════════════════
// ACTION GENERATION
// ═══════════════════════════════════════════════════════════════

function generateActions(
  regressions: RegressionDetail[]
): RegressionAction[] {
  const actions: RegressionAction[] = [];

  const hasSevere = regressions.some((r) => r.severity === "severe");
  const hasModerate = regressions.some((r) => r.severity === "moderate");

  if (hasSevere) {
    actions.push({
      action: "pause_auto_approve",
      reason: "Severe quality regression detected — pausing all auto-approvals",
      urgency: "high",
    });
    actions.push({
      action: "alert",
      reason: "Quality regression requires human attention",
      urgency: "high",
    });
  }

  for (const r of regressions) {
    if (r.type === "approval_rate" && r.data.taskType) {
      actions.push({
        action: "demote_tier",
        reason: `Approval rate dropped for ${r.data.taskType}`,
        urgency: r.severity === "severe" ? "high" : "medium",
        affectedTaskTypes: [r.data.taskType],
      });
    }

    if (r.type === "calibration_drift") {
      actions.push({
        action: "recalibrate",
        reason: "Calibration accuracy has degraded significantly",
        urgency: "medium",
      });
    }

    if (r.type === "dimension_score" && r.severity !== "minor") {
      actions.push({
        action: "escalate_review",
        reason: `${r.data.dimension} scores declining — increasing review frequency`,
        urgency: r.severity === "severe" ? "high" : "medium",
      });
    }
  }

  return actions;
}

// ═══════════════════════════════════════════════════════════════
// HELPERS
// ═══════════════════════════════════════════════════════════════

function computeRate(events: EnrichedFeedbackEvent[], decision: string): number {
  const withDecision = events.filter((e) => e.feedback.decision);
  if (withDecision.length === 0) return 0;
  return (
    withDecision.filter((e) => e.feedback.decision?.decision === decision)
      .length / withDecision.length
  );
}

function pct(value: number): string {
  return `${(value * 100).toFixed(0)}%`;
}
