import { describe, it, expect, beforeEach, vi } from 'vitest';
import * as childProcess from 'child_process';
import * as fs from 'fs';
import { JailRuntime, useJailRuntime } from './jail-runtime.js';

vi.mock('child_process');
vi.mock('fs');

describe('JailRuntime', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Reset singleton between tests
    Reflect.set(JailRuntime as unknown as Record<string, unknown>, 'instance', undefined);
  });

  describe('detectJail', () => {
    it('returns true when running in a jail', () => {
      vi.mocked(childProcess.execSync).mockReturnValue('1\n' as never);
      const runtime = JailRuntime.getInstance();
      expect(runtime.isInJail()).toBe(true);
    });

    it('returns false when not running in a jail', () => {
      vi.mocked(childProcess.execSync).mockReturnValue('0\n' as never);
      const runtime = JailRuntime.getInstance();
      expect(runtime.isInJail()).toBe(false);
    });
  });

  describe('isLinuxEmulationEnabled', () => {
    it('returns true when Linux emulation is enabled', () => {
      vi.mocked(childProcess.execSync).mockReturnValue('YES\n' as never);
      expect(JailRuntime.isLinuxEmulationEnabled()).toBe(true);
    });

    it('returns false when Linux emulation is disabled', () => {
      vi.mocked(childProcess.execSync).mockReturnValue('NO\n' as never);
      expect(JailRuntime.isLinuxEmulationEnabled()).toBe(false);
    });
  });

  describe('validateJailEnvironment', () => {
    it('returns warnings when Linux emulation is enabled', () => {
      vi.mocked(childProcess.execSync).mockReturnValue('YES\n' as never);
      vi.mocked(fs.existsSync).mockReturnValue(true);

      const validation = JailRuntime.validateJailEnvironment();
      expect(validation.valid).toBe(true);
      expect(validation.warnings).toContain(
        'Linux emulation is enabled. Disable it for native performance.',
      );
    });

    it('returns errors when jail path does not exist', () => {
      vi.mocked(childProcess.execSync).mockImplementation(() => {
        throw new Error('Command failed');
      });
      vi.mocked(fs.existsSync).mockReturnValue(false);

      const validation = JailRuntime.validateJailEnvironment();
      expect(validation.errors).toEqual(
        expect.arrayContaining([expect.stringContaining('Jail path')]),
      );
    });
  });

  describe('getJailInfo', () => {
    it('parses jail information correctly', () => {
      const jlsOutput =
        'jid=1 name=controlplane path=/usr/local/bastille/jails/controlplane/root host.hostname=ai.clawdie.si ip4.addr=192.168.100.100';

      vi.mocked(childProcess.execSync)
        .mockReturnValueOnce('1\n' as never)
        .mockReturnValueOnce(jlsOutput as never);

      const runtime = JailRuntime.getInstance();
      expect(runtime.getJailInfo()).toEqual({
        name: 'controlplane',
        jid: 1,
        hostname: 'ai.clawdie.si',
        path: '/usr/local/bastille/jails/controlplane/root',
        ip: '192.168.100.100',
      });
    });
  });
});

describe('useJailRuntime', () => {
  it('returns true on FreeBSD with valid jail environment', () => {
    const originalPlatform = process.platform;
    Object.defineProperty(process, 'platform', { value: 'freebsd' });

    vi.mocked(childProcess.execSync).mockImplementation(() => {
      throw new Error('linux_enable not set');
    });
    vi.mocked(fs.existsSync).mockReturnValue(true);

    expect(useJailRuntime()).toBe(true);

    Object.defineProperty(process, 'platform', { value: originalPlatform });
  });

  it('returns false on non-FreeBSD platforms', () => {
    const originalPlatform = process.platform;
    Object.defineProperty(process, 'platform', { value: 'linux' });

    expect(useJailRuntime()).toBe(false);

    Object.defineProperty(process, 'platform', { value: originalPlatform });
  });
});
