/**
 * ProcessRegistry Tests
 *
 * Tests for the in-memory process registry.
 * Verifies CRUD operations for process metadata.
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { ProcessRegistry } from './registry.js';
import type { ProcessInfo } from './types.js';

describe('ProcessRegistry', () => {
  let registry: ProcessRegistry;

  // Helper to create a ProcessInfo object
  const createProcessInfo = (id: string, overrides: Partial<ProcessInfo> = {}): ProcessInfo => ({
    id,
    pid: 12345,
    command: 'node',
    args: ['server.js'],
    startedAt: new Date(),
    status: 'running',
    ...overrides,
  });

  beforeEach(() => {
    registry = new ProcessRegistry();
  });

  describe('register()', () => {
    it('should add process to registry', () => {
      const info = createProcessInfo('proc-1');
      registry.register(info);

      expect(registry.size).toBe(1);
      expect(registry.get('proc-1')).toBe(info);
    });

    it('should overwrite process with same ID', () => {
      const info1 = createProcessInfo('proc-1', { pid: 111 });
      const info2 = createProcessInfo('proc-1', { pid: 222 });

      registry.register(info1);
      registry.register(info2);

      expect(registry.size).toBe(1);
      expect(registry.get('proc-1')?.pid).toBe(222);
    });
  });

  describe('get()', () => {
    it('should retrieve registered process', () => {
      const info = createProcessInfo('proc-1');
      registry.register(info);

      const retrieved = registry.get('proc-1');
      expect(retrieved).toBe(info);
    });

    it('should return undefined for non-existent process', () => {
      const result = registry.get('non-existent');
      expect(result).toBeUndefined();
    });
  });

  describe('getAll()', () => {
    it('should return all registered processes', () => {
      const info1 = createProcessInfo('proc-1');
      const info2 = createProcessInfo('proc-2');
      const info3 = createProcessInfo('proc-3');

      registry.register(info1);
      registry.register(info2);
      registry.register(info3);

      const all = registry.getAll();
      expect(all).toHaveLength(3);
      expect(all).toContain(info1);
      expect(all).toContain(info2);
      expect(all).toContain(info3);
    });

    it('should return empty array when registry is empty', () => {
      const all = registry.getAll();
      expect(all).toEqual([]);
    });
  });

  describe('updateStatus()', () => {
    it('should change process status correctly', () => {
      const info = createProcessInfo('proc-1', { status: 'running' });
      registry.register(info);

      const result = registry.updateStatus('proc-1', 'stopped');

      expect(result).toBe(true);
      expect(registry.get('proc-1')?.status).toBe('stopped');
    });

    it('should return false for non-existent process', () => {
      const result = registry.updateStatus('non-existent', 'stopped');
      expect(result).toBe(false);
    });

    it('should update to crashed status', () => {
      const info = createProcessInfo('proc-1', { status: 'running' });
      registry.register(info);

      registry.updateStatus('proc-1', 'crashed');

      expect(registry.get('proc-1')?.status).toBe('crashed');
    });
  });

  describe('unregister()', () => {
    it('should remove process from registry', () => {
      const info = createProcessInfo('proc-1');
      registry.register(info);

      expect(registry.size).toBe(1);

      registry.unregister('proc-1');

      expect(registry.size).toBe(0);
      expect(registry.get('proc-1')).toBeUndefined();
    });

    it('should do nothing for non-existent process', () => {
      registry.register(createProcessInfo('proc-1'));

      registry.unregister('non-existent');

      expect(registry.size).toBe(1);
    });
  });

  describe('getByPid()', () => {
    it('should find process by OS PID', () => {
      const info = createProcessInfo('proc-1', { pid: 54321 });
      registry.register(info);

      const found = registry.getByPid(54321);
      expect(found).toBe(info);
    });

    it('should return undefined for unknown PID', () => {
      registry.register(createProcessInfo('proc-1', { pid: 111 }));

      const found = registry.getByPid(99999);
      expect(found).toBeUndefined();
    });
  });

  describe('clear()', () => {
    it('should remove all processes from registry', () => {
      registry.register(createProcessInfo('proc-1'));
      registry.register(createProcessInfo('proc-2'));
      registry.register(createProcessInfo('proc-3'));

      expect(registry.size).toBe(3);

      registry.clear();

      expect(registry.size).toBe(0);
      expect(registry.getAll()).toEqual([]);
    });
  });

  describe('size', () => {
    it('should return count of registered processes', () => {
      expect(registry.size).toBe(0);

      registry.register(createProcessInfo('proc-1'));
      expect(registry.size).toBe(1);

      registry.register(createProcessInfo('proc-2'));
      expect(registry.size).toBe(2);

      registry.unregister('proc-1');
      expect(registry.size).toBe(1);
    });
  });
});
