/**
 * Sentinel Redis event payload tests (N3)
 */

import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
import {
  buildAuditLogEvent,
  buildKillEvent,
  buildPolicyViolationEvent,
} from '../adapters/redis-sentinel-publisher.js';
import {
  resetMetrics,
  sentinelKillsTotal,
  sentinelPolicyViolationsTotal,
} from '../metrics/index.js';

describe('Sentinel Redis events (N3)', () => {
  beforeEach(() => {
    resetMetrics();
  });

  afterEach(() => {
    resetMetrics();
  });

  describe('event payloads', () => {
    it('buildPolicyViolationEvent includes deny action and policy fields', () => {
      const event = buildPolicyViolationEvent('run-1', {
        policy: 'timeout',
        reason: 'Run exceeded maximum duration',
        threshold: 60_000,
        actual: 120_000,
        action: 'deny',
      });

      expect(event.type).toBe('policy.violation');
      expect(event.runId).toBe('run-1');
      expect(event.data).toMatchObject({
        policy: 'timeout',
        action: 'deny',
        threshold: 60_000,
        actual: 120_000,
      });
    });

    it('buildKillEvent includes stable output and trigger', () => {
      const event = buildKillEvent('run-2', 'policy_violation:idle', 'policy');

      expect(event.type).toBe('kill');
      expect(event.data).toMatchObject({
        reason: 'policy_violation:idle',
        trigger: 'policy',
        source: 'sentinel',
        policy: 'idle',
        output: {
          error: 'Run terminated by Sentinel',
          source: 'sentinel',
          action: 'deny',
          reason: 'policy_violation:idle',
          policy: 'idle',
        },
      });
    });

    it('buildAuditLogEvent wraps kill audit records', () => {
      const event = buildAuditLogEvent('run-3', 'kill', {
        reason: 'manual_cancellation',
        trigger: 'manual',
      });

      expect(event.type).toBe('audit.log');
      expect(event.data.action).toBe('kill');
      expect(event.data.reason).toBe('manual_cancellation');
    });
  });

  describe('Prometheus counters', () => {
    it('sentinelPolicyViolationsTotal labels by policy', async () => {
      sentinelPolicyViolationsTotal.inc({ policy: 'token_cap' });

      const metrics = await sentinelPolicyViolationsTotal.get();
      const row = metrics.values.find((v) => v.labels.policy === 'token_cap');
      expect(row?.value).toBe(1);
    });

    it('sentinelKillsTotal labels by trigger', async () => {
      sentinelKillsTotal.inc({ trigger: 'manual' });
      sentinelKillsTotal.inc({ trigger: 'policy' });

      const metrics = await sentinelKillsTotal.get();
      expect(metrics.values.find((v) => v.labels.trigger === 'manual')?.value).toBe(1);
      expect(metrics.values.find((v) => v.labels.trigger === 'policy')?.value).toBe(1);
    });
  });
});
