/**
 * DC-080: Plugin manager tests
 */
const fs = require('fs');
const path = require('path');
const os = require('os');
const { PluginManager } = require('../../src/plugins/plugin-manager');

describe('DC-080: Plugin Manager', () => {
  let tmpDir, manager;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dc-plugins-'));
    manager = new PluginManager({
      dataDir: tmpDir,
      log: { info: jest.fn(), error: jest.fn() },
    });
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  describe('loadAll()', () => {
    it('creates plugin directory if it does not exist', async () => {
      const pluginDir = path.join(tmpDir, 'plugins');
      expect(fs.existsSync(pluginDir)).toBe(false);
      await manager.loadAll();
      expect(fs.existsSync(pluginDir)).toBe(true);
    });

    it('loads successfully with empty plugin dir', async () => {
      await manager.loadAll();
      expect(manager.plugins.size).toBe(0);
      expect(manager.loaded).toBe(true);
    });

    it('skips hidden directories', async () => {
      const hiddenDir = path.join(tmpDir, 'plugins', '.hidden');
      fs.mkdirSync(hiddenDir, { recursive: true });
      await manager.loadAll();
      expect(manager.plugins.size).toBe(0);
    });
  });

  describe('loadOne()', () => {
    it('loads a plugin with valid manifest', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'test-plugin');
      fs.mkdirSync(pluginDir, { recursive: true });
      fs.writeFileSync(
        path.join(pluginDir, 'manifest.json'),
        JSON.stringify({
          name: 'test-plugin',
          version: '1.0.0',
          description: 'A test plugin',
        })
      );

      await manager.loadOne(pluginDir);
      expect(manager.plugins.has('test-plugin')).toBe(true);
    });

    it('throws if manifest.json is missing', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'no-manifest');
      fs.mkdirSync(pluginDir, { recursive: true });

      await expect(manager.loadOne(pluginDir)).rejects.toThrow('manifest.json');
    });

    it('throws if manifest lacks name or version', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'invalid');
      fs.mkdirSync(pluginDir, { recursive: true });
      fs.writeFileSync(
        path.join(pluginDir, 'manifest.json'),
        JSON.stringify({ description: 'no name' })
      );

      await expect(manager.loadOne(pluginDir)).rejects.toThrow('name and version');
    });

    it('throws on duplicate plugin name', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'dup');
      fs.mkdirSync(pluginDir, { recursive: true });
      fs.writeFileSync(
        path.join(pluginDir, 'manifest.json'),
        JSON.stringify({ name: 'dup', version: '1.0.0' })
      );

      await manager.loadOne(pluginDir);
      await expect(manager.loadOne(pluginDir)).rejects.toThrow('already loaded');
    });
  });

  describe('unload()', () => {
    it('unloads a loaded plugin', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'removable');
      fs.mkdirSync(pluginDir, { recursive: true });
      fs.writeFileSync(
        path.join(pluginDir, 'manifest.json'),
        JSON.stringify({ name: 'removable', version: '1.0.0' })
      );

      await manager.loadOne(pluginDir);
      expect(manager.plugins.has('removable')).toBe(true);

      manager.unload('removable');
      expect(manager.plugins.has('removable')).toBe(false);
    });

    it('returns false for unknown plugin', () => {
      expect(manager.unload('nonexistent')).toBe(false);
    });
  });

  describe('list()', () => {
    it('returns empty array when no plugins', () => {
      expect(manager.list()).toEqual([]);
    });

    it('returns plugin metadata', async () => {
      const pluginDir = path.join(tmpDir, 'plugins', 'listed');
      fs.mkdirSync(pluginDir, { recursive: true });
      fs.writeFileSync(
        path.join(pluginDir, 'manifest.json'),
        JSON.stringify({ name: 'listed', version: '2.0.0', description: 'Test' })
      );

      await manager.loadOne(pluginDir);
      const list = manager.list();
      expect(list).toHaveLength(1);
      expect(list[0].name).toBe('listed');
      expect(list[0].version).toBe('2.0.0');
    });
  });

  describe('executeHook()', () => {
    it('returns empty results when no plugins have the hook', async () => {
      await manager.loadAll();
      const results = await manager.executeHook('service:health-check');
      expect(results).toEqual([]);
    });
  });

  describe('getWidgets()', () => {
    it('returns empty array by default', () => {
      expect(manager.getWidgets()).toEqual([]);
    });
  });

  describe('getServiceTypes()', () => {
    it('returns empty array by default', () => {
      expect(manager.getServiceTypes()).toEqual([]);
    });
  });
});
