import { describe, it, expect, vi, beforeEach } from 'vitest';
import { initAuditLogger } from '../audit/index.js';
import {
  ELEVATION_DISABLE_CONFIRM_TEXT,
  ELEVATION_ENABLE_CONFIRM_TEXT,
  ELEVATION_INVALID_DURATION_TEXT,
  ELEVATION_USAGE_TEXT,
  getElevationStatusMessage,
  getElevationWindow,
  parseElevationDurationToMs,
  setElevationFromInput,
  type ElevationStore,
} from './elevation.js';

function createStore(initial?: Record<string, string>): ElevationStore {
  const values = new Map<string, string>(Object.entries(initial ?? {}));
  return {
    get: (key) => values.get(key),
    set: (key, value) => {
      values.set(key, value);
    },
    delete: (key) => {
      values.delete(key);
    },
  };
}

describe('security/elevation', () => {
  const audit = {
    securityElevationEnabled: vi.fn(),
    securityElevationDisabled: vi.fn(),
    securityElevationExpired: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
    initAuditLogger(audit as unknown as Parameters<typeof initAuditLogger>[0]);
  });

  it('parses elevation durations', () => {
    expect(parseElevationDurationToMs('30s')).toBe(30_000);
    expect(parseElevationDurationToMs('10m')).toBe(600_000);
    expect(parseElevationDurationToMs('2h')).toBe(7_200_000);
    expect(parseElevationDurationToMs('1d')).toBe(86_400_000);
    expect(parseElevationDurationToMs('bad')).toBeNull();
  });

  it('returns off status when no elevation is active', () => {
    const store = createStore();
    expect(getElevationStatusMessage(store)).toBe('Elevated mode: off');
  });

  it('returns on status with remaining seconds and reason', () => {
    const store = createStore({
      'elevation.until_ms': String(20_000),
      'elevation.id': 'e1',
      'elevation.reason': 'maintenance',
    });
    const message = getElevationStatusMessage(store, { nowMs: 10_500, reasonSeparator: ' - ' });
    expect(message).toBe('Elevated mode: on (10s remaining) - maintenance');
  });

  it('expires stale elevation and optionally reports expired status', () => {
    const store = createStore({
      'elevation.until_ms': String(5_000),
      'elevation.id': 'e1',
      'elevation.reason': 'test',
    });

    expect(getElevationStatusMessage(store, { nowMs: 6_000 })).toBe('Elevated mode: off');
    expect(getElevationStatusMessage(store, { nowMs: 6_000, showExpiredSuffix: true })).toBe('Elevated mode: off');

    const store2 = createStore({
      'elevation.until_ms': String(5_000),
      'elevation.id': 'e2',
      'elevation.reason': 'test2',
    });
    const message = getElevationStatusMessage(store2, {
      nowMs: 6_000,
      showExpiredSuffix: true,
      auditContext: { sessionId: 'ws:s1', channel: 'ws', sender: 'c1' },
    });
    expect(message).toBe('Elevated mode: off (expired)');
    expect(audit.securityElevationExpired).toHaveBeenCalledWith(expect.objectContaining({
      session_id: 'ws:s1',
      elevation_id: 'e2',
      until_ms: 5000,
    }));
  });

  it('enables elevation from command input', () => {
    const store = createStore();
    const message = setElevationFromInput(store, '10m reason text --yes', {
      nowMs: 1_000,
      idGenerator: () => 'id-1',
      auditContext: { sessionId: 'ws:s1', channel: 'ws', sender: 'c1' },
    });
    expect(message).toBe('Elevated mode: on until 1970-01-01T00:10:01.000Z');
    expect(getElevationWindow(store, { nowMs: 1_001 }).window).toEqual({
      untilMs: 601000,
      id: 'id-1',
      reason: 'reason text',
    });
    expect(audit.securityElevationEnabled).toHaveBeenCalledWith(expect.objectContaining({
      session_id: 'ws:s1',
      elevation_id: 'id-1',
      ttl_ms: 600000,
    }));
  });

  it('disables elevation from command input', () => {
    const store = createStore({
      'elevation.until_ms': String(20_000),
      'elevation.id': 'e1',
      'elevation.reason': 'cleanup',
    });
    const message = setElevationFromInput(store, 'off --yes', {
      auditContext: { sessionId: 'ws:s1', channel: 'ws', sender: 'c1' },
    });
    expect(message).toBe('Elevated mode: off');
    expect(getElevationWindow(store)).toEqual({ expired: false });
    expect(audit.securityElevationDisabled).toHaveBeenCalledWith(expect.objectContaining({
      session_id: 'ws:s1',
      elevation_id: 'e1',
      reason: 'cleanup',
    }));
  });

  it('validates command usage and confirmation', () => {
    const store = createStore();
    expect(setElevationFromInput(store, '')).toBe(ELEVATION_USAGE_TEXT);
    expect(setElevationFromInput(store, 'off')).toBe(ELEVATION_DISABLE_CONFIRM_TEXT);
    expect(setElevationFromInput(store, '10m reason')).toBe(ELEVATION_ENABLE_CONFIRM_TEXT);
    expect(setElevationFromInput(store, '10x reason --yes')).toBe(ELEVATION_INVALID_DURATION_TEXT);
  });
});
