// tests/reflection/introspection.spec.ts
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import {
  startIntrospectionEngine,
  stopIntrospectionEngine,
  computeSignalsNow,
  _resetIntrospectionForTests,
} from '@/lib/reflection/introspection';
import { SIGNALS } from '@/lib/reflection/types';
import { getLatestSignals } from '@/lib/reflection/memory';

/**
 * Reflection Introspection Engine Tests
 *
 * Tests ensure:
 * - Respect of REFLECTION_ENABLED flag
 * - Signal computation at fixed intervals
 * - Accuracy of WINDOW_CHURN and FOCUS_STABILITY signals
 * - Reset behavior per interval
 * - Manual trigger with computeSignalsNow()
 */

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

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

  // ---------------------------------------------------------
  // 1. Flag Behavior
  // ---------------------------------------------------------
  it('should not run if REFLECTION_ENABLED is false', async () => {
    const originalEnv = process.env.REFLECTION_ENABLED;
    process.env.REFLECTION_ENABLED = 'false';

    const spy = vi.spyOn(global.console, 'log').mockImplementation(() => {});
    startIntrospectionEngine();
    vi.advanceTimersByTime(6000);

    expect(spy).not.toHaveBeenCalledWith(expect.stringContaining('🪞 Running introspection'));
    process.env.REFLECTION_ENABLED = originalEnv;
  });

  // ---------------------------------------------------------
  // 2. Signal Interval Computation
  // ---------------------------------------------------------
  it('should compute signals at a regular interval', async () => {
    process.env.REFLECTION_ENABLED = 'true';
    startIntrospectionEngine(2000); // interval = 2s

    vi.advanceTimersByTime(10000);
    const signals = getLatestSignals();

    expect(Array.isArray(signals)).toBe(true);
    expect(signals.length).toBeGreaterThan(0);
    expect(signals[0]).toHaveProperty('type');
  });

  // ---------------------------------------------------------
  // 3. WINDOW_CHURN signal accuracy
  // ---------------------------------------------------------
  it('should correctly compute WINDOW_CHURN signal', () => {
    process.env.REFLECTION_ENABLED = 'true';

    // simulate multiple open/close actions
    startIntrospectionEngine(1000);
    vi.advanceTimersByTime(5000);

    const signals = getLatestSignals();
    const churn = signals.find((s) => s.type === SIGNALS.WINDOW_CHURN);

    expect(churn).toBeDefined();
    expect(typeof churn?.value).toBe('number');
    expect(churn?.timestamp).toBeGreaterThanOrEqual(0);
  });

  // ---------------------------------------------------------
  // 4. FOCUS_STABILITY signal accuracy
  // ---------------------------------------------------------
  it('should correctly compute FOCUS_STABILITY signal', () => {
    process.env.REFLECTION_ENABLED = 'true';
    startIntrospectionEngine(1000);

    vi.advanceTimersByTime(3000);

    const signals = getLatestSignals();
    const focus = signals.find((s) => s.type === SIGNALS.FOCUS_STABILITY);

    expect(focus).toBeDefined();
    expect(focus?.value).toBeGreaterThanOrEqual(0);
    expect(focus?.value).toBeLessThanOrEqual(1);
  });

  // ---------------------------------------------------------
  // 5. Aggregator reset between intervals
  // ---------------------------------------------------------
  it('should reset the aggregator after each interval', () => {
    process.env.REFLECTION_ENABLED = 'true';
    startIntrospectionEngine(1000);

    vi.advanceTimersByTime(1000);
    const first = getLatestSignals();
    vi.advanceTimersByTime(1000);
    const second = getLatestSignals();

    expect(second.length).toBeGreaterThanOrEqual(first.length);
    expect(second).not.toBe(first); // ensure new memory batch
  });

  // ---------------------------------------------------------
  // 6. Manual computation
  // ---------------------------------------------------------
  it('should allow manual signal computation via computeSignalsNow()', () => {
    process.env.REFLECTION_ENABLED = 'true';
    const signals = computeSignalsNow();

    expect(Array.isArray(signals)).toBe(true);
    expect(signals.length).toBe(2); // churn + focus
    expect(signals[0]).toHaveProperty('type');
    expect(signals[0]).toHaveProperty('timestamp');
  });
});
