/**
 * HTTP apply → disk → simulated restart (proves route wiring, not UI-only).
 */

import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
import Fastify from 'fastify';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { Sentinel } from '@4runr/sentinel';
import {
  getSentinelLimitsFilePath,
  applyPersistedSentinelConfig,
  hydrateSentinelConfigFromDisk,
} from '../security/sentinel-config-store.js';

jest.mock('../middleware/rateLimit.js', () => ({
  writeRateLimit: async () => {},
  readRateLimit: async () => {},
}));

jest.mock('../middleware/auth.js', () => ({
  requireAuth: async () => {},
}));

describe('POST /api/sentinel/policies/custom persistence', () => {
  const originalAppData = process.env['APPDATA'];
  let tmpDir: string;
  let app: ReturnType<typeof Fastify>;

  beforeEach(async () => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '4runr-sentinel-http-'));
    process.env['APPDATA'] = tmpDir;
    delete process.env['RUN_IDLE_MS'];
    delete process.env['SENTINEL_IDLE_MS'];
    Sentinel.resetInstance();

    const { sentinelPolicyRoutes } = await import('../routes/sentinel-policies.js');
    app = Fastify();
    await sentinelPolicyRoutes(app);
    await app.ready();
  });

  afterEach(async () => {
    await app.close();
    Sentinel.resetInstance();
    if (originalAppData === undefined) delete process.env['APPDATA'];
    else process.env['APPDATA'] = originalAppData;
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  it('writes sentinel-limits.json and reloads after simulated Gateway restart', async () => {
    const distinctiveIdle = 77_777;

    const res = await app.inject({
      method: 'POST',
      url: '/api/sentinel/policies/custom',
      payload: {
        enabled: true,
        runMaxDurationMs: 120_000,
        runMaxTokens: 16_000,
        runIdleMs: distinctiveIdle,
        loopWindow: 15,
        loopMax: 5,
        runMaxCost: 1.5,
      },
    });

    expect(res.statusCode).toBe(200);
    const body = res.json() as { success?: boolean; config?: { runIdleMs?: number } };
    expect(body.success).toBe(true);
    expect(body.config?.runIdleMs).toBe(distinctiveIdle);

    const filePath = getSentinelLimitsFilePath();
    expect(fs.existsSync(filePath)).toBe(true);
    const onDisk = JSON.parse(fs.readFileSync(filePath, 'utf8')) as {
      config: { runIdleMs: number };
    };
    expect(onDisk.config.runIdleMs).toBe(distinctiveIdle);

    Sentinel.resetInstance();
    const sentinel = Sentinel.getInstance();
    expect(applyPersistedSentinelConfig(sentinel)).toBe(true);
    expect(sentinel.getConfig().runIdleMs).toBe(distinctiveIdle);

    Sentinel.resetInstance();
    const stale = Sentinel.getInstance();
    expect(stale.getConfig().runIdleMs).not.toBe(distinctiveIdle);

    hydrateSentinelConfigFromDisk(stale);
    expect(stale.getConfig().runIdleMs).toBe(distinctiveIdle);
  });
});
