/**
 * Diminishing Review System — 5-Tier Autonomy
 *
 * As Buba proves competence in specific task types, HITL frequency decreases:
 *
 * Tier 1: Always review (new task types, low confidence)
 * Tier 2: Review with smart defaults pre-selected
 * Tier 3: Auto-approve with async audit
 * Tier 4: Auto-approve, sample 10% for spot checks
 * Tier 5: Full autonomy (earned through consistent high scores)
 *
 * Regression: If quality scores drop, auto-escalate review frequency.
 */

import * as fs from "node:fs";
import * as path from "node:path";
import type {
  AutonomyLevel,
  AutonomyTier,
  RegressionStatus,
  TIER_THRESHOLDS,
} from "../types.js";

// Re-import the thresholds
const THRESHOLDS: Record<AutonomyTier, { minApprovals: number; minRate: number }> = {
  1: { minApprovals: 0, minRate: 0 },
  2: { minApprovals: 10, minRate: 0.80 },
  3: { minApprovals: 25, minRate: 0.85 },
  4: { minApprovals: 50, minRate: 0.90 },
  5: { minApprovals: 100, minRate: 0.95 },
};

const AUTONOMY_FILE = "autonomy-levels.json";

// ═══════════════════════════════════════════════════════════════
// AUTONOMY LEVEL MANAGEMENT
// ═══════════════════════════════════════════════════════════════

function getAutonomyPath(dataDir: string): string {
  return path.join(dataDir, AUTONOMY_FILE);
}

/**
 * Load autonomy levels for all task types.
 */
export function loadAutonomyLevels(
  dataDir: string
): Record<string, AutonomyLevel> {
  const filePath = getAutonomyPath(dataDir);
  if (!fs.existsSync(filePath)) return {};

  try {
    return JSON.parse(fs.readFileSync(filePath, "utf-8"));
  } catch {
    return {};
  }
}

/**
 * Save autonomy levels.
 */
function saveAutonomyLevels(
  dataDir: string,
  levels: Record<string, AutonomyLevel>
): void {
  const dir = path.dirname(getAutonomyPath(dataDir));
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  fs.writeFileSync(
    getAutonomyPath(dataDir),
    JSON.stringify(levels, null, 2),
    "utf-8"
  );
}

/**
 * Get the autonomy level for a specific task type.
 * Returns Tier 1 if unknown.
 */
export function getAutonomyLevel(
  dataDir: string,
  taskType: string
): AutonomyLevel {
  const levels = loadAutonomyLevels(dataDir);
  return (
    levels[taskType] ?? {
      taskType,
      currentTier: 1 as AutonomyTier,
      approvalRate: 0,
      totalReviews: 0,
      consecutiveApprovals: 0,
      lastRegression: null,
      lastUpdated: new Date().toISOString(),
    }
  );
}

// ═══════════════════════════════════════════════════════════════
// REVIEW DECISION
// ═══════════════════════════════════════════════════════════════

export interface ReviewDecision {
  /** Whether this item needs human review */
  needsReview: boolean;
  /** Current autonomy tier */
  tier: AutonomyTier;
  /** Type of review if needed */
  reviewType:
    | "full"           // Tier 1: Full review
    | "smart_defaults" // Tier 2: Review with pre-selected defaults
    | "async_audit"    // Tier 3: Auto-approved, queued for async audit
    | "spot_check"     // Tier 4: 10% sampling
    | "autonomous"     // Tier 5: No review
    ;
  /** Reason for this decision */
  reason: string;
  /** Confidence in this auto-decision (0-1) */
  confidence: number;
}

/**
 * Decide whether a task needs human review based on autonomy level.
 */
export function decideReview(
  dataDir: string,
  taskType: string,
  aiConfidence: number
): ReviewDecision {
  const level = getAutonomyLevel(dataDir, taskType);

  // Always review if AI confidence is very low
  if (aiConfidence < 0.4) {
    return {
      needsReview: true,
      tier: level.currentTier,
      reviewType: "full",
      reason: "AI confidence too low for any autonomous action",
      confidence: aiConfidence,
    };
  }

  switch (level.currentTier) {
    case 1:
      return {
        needsReview: true,
        tier: 1,
        reviewType: "full",
        reason: `New/unproven task type (${level.totalReviews} reviews)`,
        confidence: aiConfidence,
      };

    case 2:
      return {
        needsReview: true,
        tier: 2,
        reviewType: "smart_defaults",
        reason: `Tier 2: ${level.totalReviews} reviews, ${(level.approvalRate * 100).toFixed(0)}% approval — showing smart defaults`,
        confidence: aiConfidence,
      };

    case 3:
      return {
        needsReview: false,
        tier: 3,
        reviewType: "async_audit",
        reason: `Tier 3: Auto-approved, queued for async audit (${(level.approvalRate * 100).toFixed(0)}% historical)`,
        confidence: aiConfidence,
      };

    case 4: {
      // 10% spot check — deterministic based on total reviews
      const isSpotCheck = level.totalReviews % 10 === 0;
      return {
        needsReview: isSpotCheck,
        tier: 4,
        reviewType: isSpotCheck ? "spot_check" : "autonomous",
        reason: isSpotCheck
          ? `Tier 4: Spot check (1 in 10)`
          : `Tier 4: Auto-approved (${level.totalReviews} reviews, ${(level.approvalRate * 100).toFixed(0)}% rate)`,
        confidence: aiConfidence,
      };
    }

    case 5:
      return {
        needsReview: false,
        tier: 5,
        reviewType: "autonomous",
        reason: `Tier 5: Full autonomy earned (${level.totalReviews} reviews, ${(level.approvalRate * 100).toFixed(0)}% rate)`,
        confidence: aiConfidence,
      };

    default:
      return {
        needsReview: true,
        tier: 1,
        reviewType: "full",
        reason: "Unknown tier — defaulting to full review",
        confidence: aiConfidence,
      };
  }
}

// ═══════════════════════════════════════════════════════════════
// LEVEL UPDATES
// ═══════════════════════════════════════════════════════════════

/**
 * Record a review outcome and potentially promote/demote the autonomy level.
 */
export function recordReviewOutcome(
  dataDir: string,
  taskType: string,
  approved: boolean
): {
  level: AutonomyLevel;
  promoted: boolean;
  demoted: boolean;
} {
  const levels = loadAutonomyLevels(dataDir);
  const current = levels[taskType] ?? {
    taskType,
    currentTier: 1 as AutonomyTier,
    approvalRate: 0,
    totalReviews: 0,
    consecutiveApprovals: 0,
    lastRegression: null,
    lastUpdated: new Date().toISOString(),
  };

  // Update stats
  current.totalReviews++;
  if (approved) {
    current.consecutiveApprovals++;
  } else {
    current.consecutiveApprovals = 0;
  }

  // Recalculate approval rate (exponential moving average)
  const alpha = 0.1; // Smoothing factor
  current.approvalRate =
    current.approvalRate * (1 - alpha) + (approved ? 1 : 0) * alpha;

  // For first 20 reviews, use simple average instead
  if (current.totalReviews <= 20) {
    // This is an approximation; in production we'd store all outcomes
    current.approvalRate =
      (current.approvalRate * (current.totalReviews - 1) +
        (approved ? 1 : 0)) /
      current.totalReviews;
  }

  current.lastUpdated = new Date().toISOString();

  // Check for promotion
  let promoted = false;
  let demoted = false;

  if (current.currentTier < 5) {
    const nextTier = (current.currentTier + 1) as AutonomyTier;
    const requirements = THRESHOLDS[nextTier];
    if (
      current.totalReviews >= requirements.minApprovals &&
      current.approvalRate >= requirements.minRate
    ) {
      current.currentTier = nextTier;
      promoted = true;
    }
  }

  // Check for demotion (regression)
  if (!promoted && current.currentTier > 1) {
    const currentRequirements = THRESHOLDS[current.currentTier];
    // Demote if approval rate drops below current tier's minimum
    if (current.approvalRate < currentRequirements.minRate * 0.9) {
      const previousTier = (current.currentTier - 1) as AutonomyTier;
      current.currentTier = previousTier;
      current.lastRegression = new Date().toISOString();
      demoted = true;
    }
  }

  levels[taskType] = current;
  saveAutonomyLevels(dataDir, levels);

  return { level: current, promoted, demoted };
}

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

/**
 * Check for regression in a task type's recent performance.
 * Uses a sliding window of the last N reviews.
 */
export function checkRegression(
  dataDir: string,
  taskType: string,
  recentApprovals: boolean[] // Most recent outcomes (true = approved)
): RegressionStatus {
  const level = getAutonomyLevel(dataDir, taskType);

  if (recentApprovals.length < 5) {
    return { regressed: false };
  }

  // Check last 5 reviews
  const last5 = recentApprovals.slice(-5);
  const recentRate = last5.filter(Boolean).length / last5.length;

  const currentThreshold = THRESHOLDS[level.currentTier];
  if (recentRate < currentThreshold.minRate) {
    const newTier = Math.max(1, level.currentTier - 1) as AutonomyTier;
    return {
      regressed: true,
      from: level.currentTier,
      to: newTier,
      reason: `Recent approval rate ${(recentRate * 100).toFixed(0)}% < tier ${level.currentTier} threshold ${(currentThreshold.minRate * 100).toFixed(0)}%`,
    };
  }

  return { regressed: false };
}

/**
 * Get a summary of all autonomy levels for the dashboard.
 */
export function getAutonomySummary(dataDir: string): {
  totalTaskTypes: number;
  byTier: Record<number, number>;
  recentRegressions: Array<{
    taskType: string;
    date: string;
  }>;
  averageTier: number;
} {
  const levels = loadAutonomyLevels(dataDir);
  const entries = Object.values(levels);

  const byTier: Record<number, number> = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
  const regressions: Array<{ taskType: string; date: string }> = [];

  for (const level of entries) {
    byTier[level.currentTier] = (byTier[level.currentTier] ?? 0) + 1;
    if (level.lastRegression) {
      regressions.push({
        taskType: level.taskType,
        date: level.lastRegression,
      });
    }
  }

  const avgTier =
    entries.length > 0
      ? entries.reduce((sum, l) => sum + l.currentTier, 0) / entries.length
      : 1;

  return {
    totalTaskTypes: entries.length,
    byTier,
    recentRegressions: regressions
      .sort((a, b) => b.date.localeCompare(a.date))
      .slice(0, 5),
    averageTier: Math.round(avgTier * 10) / 10,
  };
}
