/**
 * Sentinel policy evaluation — deny (kill) failure modes (N2)
 */

import { describe, it, expect } from '@jest/globals';
import { policyManager } from '@4runr/sentinel';
import type { RunState, SentinelConfig } from '@4runr/sentinel';

const baseConfig: SentinelConfig = {
  enabled: true,
  runMaxDurationMs: 60_000,
  runMaxTokens: 1000,
  runIdleMs: 30_000,
  loopWindow: 15,
  loopMax: 5,
  runMaxCost: 1.0,
};

function runningState(overrides: Partial<RunState> = {}): RunState {
  const now = Date.now();
  return {
    runId: 'run-test',
    createdAt: now - 5000,
    startedAt: now - 5000,
    tokenCount: 0,
    status: 'running',
    events: [],
    ...overrides,
  };
}

describe('Sentinel policies (N2 deny modes)', () => {
  it('timeout policy returns violation when duration exceeded', () => {
    const runState = runningState({
      startedAt: Date.now() - 120_000,
    });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations.some(v => v.policy === 'timeout')).toBe(true);
  });

  it('token_cap policy returns violation when over limit', () => {
    const runState = runningState({ tokenCount: 2000 });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations.some(v => v.policy === 'token_cap')).toBe(true);
  });

  it('idle policy returns violation when no tokens after idle threshold', () => {
    const runState = runningState({
      startedAt: Date.now() - 60_000,
      lastTokenAt: undefined,
    });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations.some(v => v.policy === 'idle')).toBe(true);
  });

  it('cost policy returns violation when cost exceeds cap', () => {
    const runState = runningState({ cost: 2.5 });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations.some(v => v.policy === 'cost')).toBe(true);
  });

  it('returns no violations for healthy running state', () => {
    const runState = runningState({
      startedAt: Date.now() - 1000,
      lastTokenAt: Date.now() - 500,
      tokenCount: 100,
      cost: 0.01,
    });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations).toHaveLength(0);
  });

  it('loop_detection policy returns violation for repetitive token pattern', () => {
    const now = Date.now();
    const tokenEvents = Array.from({ length: 10 }, (_, i) => ({
      type: 'token' as const,
      runId: 'run-test',
      at: now - (10 - i) * 1000,
      tokens: 42,
    }));
    const runState = runningState({
      startedAt: now - 20_000,
      lastTokenAt: now - 1000,
      tokenCount: 420,
      events: tokenEvents,
    });
    const violations = policyManager.evaluatePolicies('run-test', runState, baseConfig);
    expect(violations.some(v => v.policy === 'loop_detection')).toBe(true);
  });
});
