/**
 * Plugin Creator Tests
 */

import { describe, it, expect } from 'vitest';
import {
  pluginCreatorPlugin,
  generatePlugin,
  generateToolCode,
  generateHookCode,
  generateWorkerCode,
  generateAgentTypeCode,
  PLUGIN_TEMPLATES,
  type CreatePluginOptions,
} from './index.js';
import { HookEvent } from '../../src/types/index.js';

describe('Plugin Creator Plugin', () => {
  describe('pluginCreatorPlugin', () => {
    it('should have correct metadata', () => {
      expect(pluginCreatorPlugin.metadata.name).toBe('plugin-creator');
      expect(pluginCreatorPlugin.metadata.version).toBe('1.0.0');
      expect(pluginCreatorPlugin.metadata.tags).toContain('meta');
    });

    it('should register MCP tools', () => {
      const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
      expect(tools.length).toBeGreaterThan(0);

      const toolNames = tools.map(t => t.name);
      expect(toolNames).toContain('create-plugin');
      expect(toolNames).toContain('list-plugin-templates');
      expect(toolNames).toContain('generate-tool');
      expect(toolNames).toContain('generate-hook');
      expect(toolNames).toContain('generate-worker');
    });

    it('should register hooks', () => {
      const hooks = pluginCreatorPlugin.registerHooks?.() ?? [];
      expect(hooks.length).toBeGreaterThan(0);
      expect(hooks[0].name).toBe('plugin-creator-logger');
    });

    it('should register workers', () => {
      const workers = pluginCreatorPlugin.registerWorkers?.() ?? [];
      expect(workers.length).toBeGreaterThan(0);
      expect(workers[0].name).toBe('plugin-code-generator');
    });
  });

  describe('PLUGIN_TEMPLATES', () => {
    it('should have all expected templates', () => {
      const templateNames = Object.keys(PLUGIN_TEMPLATES);
      expect(templateNames).toContain('minimal');
      expect(templateNames).toContain('tool-plugin');
      expect(templateNames).toContain('hooks-plugin');
      expect(templateNames).toContain('worker-plugin');
      expect(templateNames).toContain('swarm-plugin');
      expect(templateNames).toContain('full-featured');
      expect(templateNames).toContain('security-focused');
    });

    it('should have valid template structures', () => {
      for (const [name, template] of Object.entries(PLUGIN_TEMPLATES)) {
        expect(template.name).toBeDefined();
        expect(template.description).toBeDefined();
        expect(template.category).toMatch(/^(tools|hooks|workers|swarm|full)$/);
        expect(Array.isArray(template.features)).toBe(true);
      }
    });
  });

  describe('generatePlugin', () => {
    it('should generate a minimal plugin', () => {
      const result = generatePlugin({
        name: 'test-plugin',
        version: '1.0.0',
      });

      expect(result.plugin).toBeDefined();
      expect(result.metadata.name).toBe('test-plugin');
      expect(result.metadata.version).toBe('1.0.0');
      expect(result.code).toContain("PluginBuilder('test-plugin'");
    });

    it('should generate a plugin with tools', () => {
      const result = generatePlugin({
        name: 'tools-test',
        features: { tools: true },
        toolNames: ['my-tool', 'another-tool'],
      });

      const tools = result.plugin.registerMCPTools?.() ?? [];
      expect(tools.length).toBe(2);
      expect(tools[0].name).toBe('my-tool');
      expect(tools[1].name).toBe('another-tool');
      expect(result.code).toContain('MCPToolBuilder');
    });

    it('should generate a plugin with hooks', () => {
      const result = generatePlugin({
        name: 'hooks-test',
        features: { hooks: true },
        hookEvents: [HookEvent.SessionStart, HookEvent.PostTaskComplete],
      });

      const hooks = result.plugin.registerHooks?.() ?? [];
      expect(hooks.length).toBe(2);
      expect(result.code).toContain('HookBuilder');
    });

    it('should generate a plugin with workers', () => {
      const result = generatePlugin({
        name: 'workers-test',
        features: { workers: true },
        workerTypes: ['coder', 'reviewer'],
      });

      const workers = result.plugin.registerWorkers?.() ?? [];
      expect(workers.length).toBe(2);
      expect(result.code).toContain('WorkerFactory');
    });

    it('should generate a plugin with swarm capabilities', () => {
      const result = generatePlugin({
        name: 'swarm-test',
        features: { swarm: true },
        agentTypes: ['coordinator', 'worker-agent'],
      });

      const agents = result.plugin.registerAgentTypes?.() ?? [];
      expect(agents.length).toBe(2);
      expect(result.code).toContain('AgentTypeDefinition');
    });

    it('should apply template features', () => {
      const result = generatePlugin({
        name: 'full-test',
        template: 'full-featured',
      });

      const tools = result.plugin.registerMCPTools?.() ?? [];
      const hooks = result.plugin.registerHooks?.() ?? [];
      const workers = result.plugin.registerWorkers?.() ?? [];
      const agents = result.plugin.registerAgentTypes?.() ?? [];

      expect(tools.length).toBeGreaterThan(0);
      expect(hooks.length).toBeGreaterThan(0);
      expect(workers.length).toBeGreaterThan(0);
      expect(agents.length).toBeGreaterThan(0);
    });

    it('should reject invalid plugin names', () => {
      expect(() => generatePlugin({ name: 'Invalid Name' })).toThrow();
      expect(() => generatePlugin({ name: '123-start' })).toThrow();
      expect(() => generatePlugin({ name: 'ab' })).toThrow(); // Too short
    });
  });

  describe('generateToolCode', () => {
    it('should generate valid tool definition', () => {
      const { definition, code } = generateToolCode('my-tool');

      expect(definition.name).toBe('my-tool');
      expect(definition.handler).toBeDefined();
      expect(code).toContain('MCPToolBuilder');
      expect(code).toContain('my-tool');
    });

    it('should sanitize invalid tool names', () => {
      const { definition } = generateToolCode('Invalid Tool Name!');
      expect(definition.name).toBe('custom-tool');
    });

    it('should create working handler', async () => {
      const { definition } = generateToolCode('test-tool');
      const result = await definition.handler({ input: 'test' });

      expect(result.content).toBeDefined();
      expect(result.content[0].type).toBe('text');
      expect(result.content[0].text).toContain('test-tool');
    });
  });

  describe('generateHookCode', () => {
    it('should generate valid hook definition', () => {
      const { definition, code } = generateHookCode(HookEvent.SessionStart);

      expect(definition.event).toBe(HookEvent.SessionStart);
      expect(definition.handler).toBeDefined();
      expect(code).toContain('HookBuilder');
      expect(code).toContain('SessionStart');
    });

    it('should create working handler', async () => {
      const { definition } = generateHookCode(HookEvent.PostTaskComplete);
      const result = await definition.handler({
        event: HookEvent.PostTaskComplete,
        data: { taskId: '123' },
        timestamp: new Date(),
      });

      expect(result.success).toBe(true);
    });
  });

  describe('generateWorkerCode', () => {
    it('should generate valid worker definitions for known types', () => {
      const types = ['coder', 'reviewer', 'tester', 'researcher', 'planner', 'coordinator', 'security', 'performance'];

      for (const type of types) {
        const { definition, code } = generateWorkerCode(type);

        expect(definition.type).toBe(type);
        expect(definition.name).toBe(`${type}-worker`);
        expect(definition.capabilities.length).toBeGreaterThan(0);
        expect(code).toContain('WorkerFactory');
      }
    });

    it('should fallback to specialized for unknown types', () => {
      const { definition, code } = generateWorkerCode('custom-type');

      expect(definition.type).toBe('specialized');
      expect(code).toContain('createSpecialized');
    });
  });

  describe('generateAgentTypeCode', () => {
    it('should generate valid agent type definition', () => {
      const { definition, code } = generateAgentTypeCode('coordinator');

      expect(definition.type).toBe('coordinator');
      expect(definition.name).toBe('coordinator Agent');
      expect(definition.model).toBe('claude-sonnet-4-6');
      expect(code).toContain('AgentTypeDefinition');
    });

    it('should sanitize invalid agent type names', () => {
      const { definition } = generateAgentTypeCode('Invalid Agent!');
      expect(definition.type).toBe('custom-agent');
    });
  });
});

describe('MCP Tool Handlers', () => {
  it('create-plugin tool should work', async () => {
    const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
    const createTool = tools.find(t => t.name === 'create-plugin');

    expect(createTool).toBeDefined();

    const result = await createTool!.handler({
      name: 'test-created-plugin',
      version: '1.0.0',
      template: 'tool-plugin',
    });

    expect(result.content[0].text).toContain('test-created-plugin');
    expect(result.content[0].text).toContain('created successfully');
  });

  it('list-plugin-templates tool should work', async () => {
    const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
    const listTool = tools.find(t => t.name === 'list-plugin-templates');

    expect(listTool).toBeDefined();

    const result = await listTool!.handler({});

    expect(result.content[0].text).toContain('Available Plugin Templates');
    expect(result.content[0].text).toContain('minimal');
    expect(result.content[0].text).toContain('full-featured');
  });

  it('generate-tool tool should work', async () => {
    const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
    const genTool = tools.find(t => t.name === 'generate-tool');

    expect(genTool).toBeDefined();

    const result = await genTool!.handler({ name: 'my-custom-tool' });

    expect(result.content[0].text).toContain('Generated Tool');
    expect(result.content[0].text).toContain('my-custom-tool');
    expect(result.content[0].text).toContain('MCPToolBuilder');
  });

  it('generate-hook tool should work', async () => {
    const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
    const genHook = tools.find(t => t.name === 'generate-hook');

    expect(genHook).toBeDefined();

    const result = await genHook!.handler({ event: HookEvent.SessionStart });

    expect(result.content[0].text).toContain('Generated Hook');
    expect(result.content[0].text).toContain('HookBuilder');
  });

  it('generate-worker tool should work', async () => {
    const tools = pluginCreatorPlugin.registerMCPTools?.() ?? [];
    const genWorker = tools.find(t => t.name === 'generate-worker');

    expect(genWorker).toBeDefined();

    const result = await genWorker!.handler({ type: 'coder' });

    expect(result.content[0].text).toContain('Generated Worker');
    expect(result.content[0].text).toContain('WorkerFactory');
  });
});
