// tests/reflection/feedback.spec.ts
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { makeDecision, applyDecisions, _resetFeedbackForTests } from '@/lib/reflection/feedback';
import {
  _resetPolicyManager,
  getPolicyValue,
  applyPolicyAdjustments,
} from '@/lib/reflection/policy';
import { SIGNALS } from '@/lib/reflection/types';
import type { EvaluationResult } from '@/lib/reflection/types';

/**
 * Reflection Feedback Engine Tests
 *
 * Verifies:
 * - Decision generation for CRITICAL/NORMAL evaluations
 * - Cooldown behavior correctness
 * - Force parameter bypasses cooldown
 * - Proper policy updates applied
 * - Clean isolation of timers between tests
 */

describe('Reflection Feedback Engine', () => {
  beforeEach(() => {
    vi.useRealTimers();
    vi.useFakeTimers();
    vi.setSystemTime(0);
    _resetFeedbackForTests?.();
    _resetPolicyManager();
  });

  afterEach(() => {
    vi.runOnlyPendingTimers();
    vi.useRealTimers();
    vi.restoreAllMocks();
  });

  // ---------------------------------------------------------
  // 1. Decision Generation Logic
  // ---------------------------------------------------------
  it('should propose a decision for a CRITICAL evaluation', () => {
    const evaluation: EvaluationResult = {
      signal: {
        type: SIGNALS.WINDOW_CHURN,
        value: 4.8,
        timestamp: 1000,
        metadata: { opens: 21, closes: 1, interval: 5000 },
      },
      status: 'CRITICAL',
      slo: { threshold: 4, status: 'CRITICAL' },
      timestamp: 1000,
    };

    const result = makeDecision([evaluation]);
    expect(result.length).toBe(1);
    expect(result[0].action).toBe('THROTTLE_WINDOWS');
    expect(result[0].mode).toBe('PROPOSED');
  });

  it('should not propose a decision for a NORMAL evaluation', () => {
    const evaluation: EvaluationResult = {
      signal: {
        type: SIGNALS.FOCUS_STABILITY,
        value: 0.9,
        timestamp: 1500,
        metadata: { count: 8, interval: 5000 },
      },
      status: 'NORMAL',
      slo: { threshold: 4, status: 'NORMAL' },
      timestamp: 1500,
    };

    const result = makeDecision([evaluation]);
    expect(result.length).toBe(0);
  });

  // ---------------------------------------------------------
  // 2. Policy Application Tests
  // ---------------------------------------------------------
  it('should apply decisions and update policy immediately when forced', () => {
    const evaluation: EvaluationResult = {
      signal: {
        type: SIGNALS.WINDOW_CHURN,
        value: 5.5,
        timestamp: 2000,
        metadata: { opens: 25, closes: 0, interval: 5000 },
      },
      status: 'CRITICAL',
      slo: { threshold: 4, status: 'CRITICAL' },
      timestamp: 2000,
    };

    const before = getPolicyValue('THROTTLE_WINDOWS');
    expect(before).toBe(100);

    const decision = makeDecision([evaluation]);
    applyDecisions(decision, false, true); // force=true

    const after = getPolicyValue('THROTTLE_WINDOWS');
    expect(after).toBe(500);
  });

  // ---------------------------------------------------------
  // 3. Cooldown Tests
  // ---------------------------------------------------------
  it('should defer repeated decisions during the cooldown period', () => {
    const evaluation: EvaluationResult = {
      signal: {
        type: SIGNALS.WINDOW_CHURN,
        value: 5.2,
        timestamp: 3000,
        metadata: { opens: 22, closes: 0, interval: 5000 },
      },
      status: 'CRITICAL',
      slo: { threshold: 4, status: 'CRITICAL' },
      timestamp: 3000,
    };

    // First decision (should apply)
    const decision = makeDecision([evaluation]);
    applyDecisions(decision, false, true);
    const firstValue = getPolicyValue('THROTTLE_WINDOWS');
    expect(firstValue).toBe(500);

    // Reset policy manager to isolate next check
    _resetPolicyManager();

    // Second decision immediately after (should defer due to cooldown)
    applyDecisions(makeDecision([evaluation]), false, false);
    const secondValue = getPolicyValue('THROTTLE_WINDOWS');
    expect(secondValue).toBe(100);

    // Advance fake timers to simulate cooldown expiry
    vi.advanceTimersByTime(6000);

    // Now it should apply again
    applyDecisions(makeDecision([evaluation]), false, false);
    const thirdValue = getPolicyValue('THROTTLE_WINDOWS');
    expect(thirdValue).toBe(500);
  });

  // ---------------------------------------------------------
  // 4. Integration with Policy Manager
  // ---------------------------------------------------------
  it('should propagate multiple simultaneous decisions correctly', () => {
    const evaluations: EvaluationResult[] = [
      {
        signal: {
          type: SIGNALS.WINDOW_CHURN,
          value: 5.1,
          timestamp: 5000,
          metadata: { opens: 24, closes: 0, interval: 5000 },
        },
        status: 'CRITICAL',
        slo: { threshold: 4, status: 'CRITICAL' },
        timestamp: 5000,
      },
      {
        signal: {
          type: SIGNALS.FOCUS_STABILITY,
          value: 0.3,
          timestamp: 5000,
          metadata: { count: 2, interval: 5000 },
        },
        status: 'CRITICAL',
        slo: { threshold: 0.4, status: 'CRITICAL' },
        timestamp: 5000,
      },
    ];

    const decisions = makeDecision(evaluations);
    expect(decisions.length).toBeGreaterThan(0);

    applyDecisions(decisions, false, true);

    const throttle = getPolicyValue('THROTTLE_WINDOWS');
    const focusTimeout = getPolicyValue('TUNE_FOCUS_TIMEOUT');

    expect(throttle).toBe(500);
    expect(focusTimeout).toBeGreaterThan(100);
  });
});
