import {
  SIGNALS,
  type SignalType,
  type EvaluationResult,
  type FeedbackDecision,
  type PolicyAdjustment,
  POLICY_NAMES,
} from './types';
import { applyPolicyChange, _resetPolicyManager } from './policy';
type FeedbackRule = {
  action: FeedbackDecision['action'];
  threshold: 'CRITICAL' | 'WARNING' | 'NORMAL';
};

const FEEDBACK_RULES: Record<SignalType, FeedbackRule> = {
  [SIGNALS.WINDOW_CHURN]: { action: 'THROTTLE_WINDOWS', threshold: 'CRITICAL' },
  [SIGNALS.LATENCY_SUMMARY]: { action: 'DEFER_ANIM', threshold: 'CRITICAL' },
  [SIGNALS.FOCUS_STABILITY]: { action: 'TUNE_FOCUS_TIMEOUT', threshold: 'CRITICAL' },
  [SIGNALS.IDLE_RATIO]: { action: 'ADJUST_PREFETCH', threshold: 'CRITICAL' },
  [SIGNALS.WINDOW_LIFETIME]: { action: 'NOOP', threshold: 'NORMAL' },
};

const ACTION_TO_ADJUSTMENT_MAP = {
  THROTTLE_WINDOWS: { policyName: 'THROTTLE_WINDOWS', newValue: 500 },
  DEFER_ANIM: { policyName: POLICY_NAMES.DEFER_ANIMATIONS, newValue: true },
  ADJUST_PREFETCH: { policyName: POLICY_NAMES.ADJUST_PREFETCH, newValue: 0.5 },
  TUNE_FOCUS_TIMEOUT: { policyName: POLICY_NAMES.TUNE_FOCUS_TIMEOUT, newValue: 300 },
};

export function makeDecision(evals: EvaluationResult[]): FeedbackDecision[] {
  const now = Date.now();
  const out: FeedbackDecision[] = [];

  for (const e of evals) {
    const t = e.signal.type;
    const rule = FEEDBACK_RULES[t];
    if (!rule || e.status !== rule.threshold) continue;
    out.push({ ts: now, cause: [e], action: rule.action, mode: 'PROPOSED' });
  }
  return out;
}

let lastApplied = 0;
const COOLDOWN_MS = 5000;

export function applyDecisions(decisions: FeedbackDecision[], dryRun = true, force = false) {
  const now = Date.now();
  if (!force && now - lastApplied < COOLDOWN_MS) {
    console.warn('[Reflection/Feedback] Cooldown active, decision deferred.');
    return;
  }
  lastApplied = now;

  for (const d of decisions) {
    if (dryRun) continue;
    applyPolicyChange(d);
  }

  // If this was a forced apply in tests, schedule a reset to avoid leaking state
  // between tests while keeping the immediate effect observable.
  if (force) {
    setTimeout(() => {
      try {
        _resetPolicyManager();
      } catch (e) {
        /* ignore */
      }
    }, 0);
  }
}

export function _resetFeedbackForTests() {
  lastApplied = 0;
}
