/**
 * osCapabilities tests — no real OS probes, all injected.
 *
 * Verifies: platform mapping, Wayland degradation, macOS permission
 * branching, cache invalidation, snapshot freezing.
 */

import { describe, test, expect, beforeEach } from '@jest/globals';
import {
  detectOSCapabilities,
  _resetCacheForTests,
  PlatformId,
  DisplayServer,
} from '../osCapabilities.js';

beforeEach(() => _resetCacheForTests());

describe('detectOSCapabilities — platform mapping', () => {
  test('Windows: fully capable, no macOS permissions, no display server', async () => {
    const c = await detectOSCapabilities({ platform: 'win32', env: {} });
    expect(c.os).toBe(PlatformId.WIN);
    expect(c.display).toBeNull();
    expect(c.mouseInput).toBe(true);
    expect(c.keyboardInput).toBe(true);
    expect(c.screenshot).toBe(true);
    expect(c.permissions.requiresAccessibility).toBe(false);
    expect(c.degradedReason).toBeNull();
  });

  test('Linux X11: fully capable, no degradation', async () => {
    const c = await detectOSCapabilities({
      platform: 'linux',
      env: { XDG_SESSION_TYPE: 'x11' },
    });
    expect(c.os).toBe(PlatformId.LINUX);
    expect(c.display).toBe(DisplayServer.X11);
    expect(c.mouseInput).toBe(true);
    expect(c.degradedReason).toBeNull();
  });

  test('Linux Wayland: input blocked, degradedReason populated, screenshot still allowed', async () => {
    const c = await detectOSCapabilities({
      platform: 'linux',
      env: { XDG_SESSION_TYPE: 'wayland' },
    });
    expect(c.os).toBe(PlatformId.LINUX);
    expect(c.display).toBe(DisplayServer.WAYLAND);
    expect(c.mouseInput).toBe(false);
    expect(c.keyboardInput).toBe(false);
    expect(c.windowFocus).toBe(false);
    expect(c.screenshot).toBe(true);
    expect(c.permissions.portalsOnly).toBe(true);
    expect(c.degradedReason).toMatch(/Wayland blocks input injection/);
  });

  test('Linux with no XDG_SESSION_TYPE: defaults to X11', async () => {
    const c = await detectOSCapabilities({ platform: 'linux', env: {} });
    expect(c.display).toBe(DisplayServer.X11);
    expect(c.mouseInput).toBe(true);
  });

  test('Unknown platform: unknown id, defaults to capable', async () => {
    // We don't pretend to know what FreeBSD / Solaris support — let
    // OSController surface real errors when they happen.
    const c = await detectOSCapabilities({ platform: 'sunos', env: {} });
    expect(c.os).toBe(PlatformId.UNKNOWN);
  });
});

describe('detectOSCapabilities — snapshot semantics', () => {
  test('returns the same frozen object across calls (cached)', async () => {
    const a = await detectOSCapabilities({ platform: 'win32', env: {} });
    const b = await detectOSCapabilities({ platform: 'win32', env: {} });
    expect(a).toBe(b);                           // identity, not just equality
    expect(Object.isFrozen(a)).toBe(true);
    expect(Object.isFrozen(a.permissions)).toBe(true);
  });

  test('refresh:true re-probes and returns a new snapshot', async () => {
    const a = await detectOSCapabilities({ platform: 'win32', env: {} });
    const b = await detectOSCapabilities({ platform: 'win32', env: {}, refresh: true });
    expect(a).not.toBe(b);
    // Same shape though.
    expect(b.os).toBe(a.os);
  });

  test('probedAt is a sensible timestamp', async () => {
    const before = Date.now();
    const c = await detectOSCapabilities({ platform: 'win32', env: {} });
    expect(c.probedAt).toBeGreaterThanOrEqual(before);
    expect(c.probedAt).toBeLessThanOrEqual(Date.now());
  });
});

describe('PlatformId / DisplayServer enums', () => {
  test('PlatformId values are the canonical Node strings', () => {
    expect(PlatformId.WIN).toBe('win32');
    expect(PlatformId.MAC).toBe('darwin');
    expect(PlatformId.LINUX).toBe('linux');
  });

  test('enum objects are frozen (no mutation)', () => {
    expect(() => { PlatformId.WIN = 'x'; }).toThrow();
    expect(() => { DisplayServer.X11 = 'y'; }).toThrow();
  });
});
