import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { setupProductRequirements } from '../index.js';
import { ProductRequirementsStore } from '../store.js';

// Mock the store
vi.mock('../store.js', () => ({
  ProductRequirementsStore: vi.fn().mockImplementation(() => ({
    createRequirement: vi.fn(),
    getRequirement: vi.fn(),
    updateRequirement: vi.fn(),
    deleteRequirement: vi.fn(),
    listRequirements: vi.fn(),
    searchRequirements: vi.fn(),
    linkRequirementToStory: vi.fn(),
    getRequirementsByStory: vi.fn(),
    getStoriesByRequirement: vi.fn(),
    updateImplementationStatus: vi.fn(),
    getRequirementsByStatus: vi.fn(),
    generateRequirementsReport: vi.fn()
  }))
}));

describe('Product Requirements Module', () => {
  let server: Server;
  let mockStore: any;
  let module: any;

  beforeEach(async () => {
    server = new Server(
      { name: 'test-server', version: '1.0.0' },
      { capabilities: {} }
    );
    
    mockStore = new ProductRequirementsStore();
    module = await setupProductRequirements(server);
  });

  describe('Module Setup', () => {
    it('should return tools and resources', () => {
      expect(module).toHaveProperty('tools');
      expect(module).toHaveProperty('resources');
      expect(module.tools).toBeInstanceOf(Array);
      expect(module.resources).toBeInstanceOf(Array);
    });

    it('should register all required tools', () => {
      const toolNames = module.tools.map((t: any) => t.name);
      expect(toolNames).toContain('create_requirement');
      expect(toolNames).toContain('list_requirements');
      expect(toolNames).toContain('get_requirement');
      expect(toolNames).toContain('update_requirement');
      expect(toolNames).toContain('delete_requirement');
      expect(toolNames).toContain('search_requirements');
      expect(toolNames).toContain('link_requirement_to_story');
      expect(toolNames).toContain('update_implementation_status');
      expect(toolNames).toContain('generate_requirements_report');
    });

    it('should register requirements resource', () => {
      expect(module.resources).toHaveLength(1);
      expect(module.resources[0].uri).toBe('atlas://requirements');
      expect(module.resources[0].name).toBe('Product Requirements');
    });
  });

  describe('create_requirement tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'create_requirement');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.required).toContain('name');
      expect(tool.inputSchema.required).toContain('type');
      expect(tool.inputSchema.required).toContain('description');
    });

    it('should validate requirement types', () => {
      const tool = module.tools.find((t: any) => t.name === 'create_requirement');
      const typeEnum = tool.inputSchema.properties.type.enum;
      expect(typeEnum).toContain('functional');
      expect(typeEnum).toContain('non-functional');
      expect(typeEnum).toContain('business');
      expect(typeEnum).toContain('technical');
      expect(typeEnum).toContain('user-interface');
      expect(typeEnum).toContain('security');
      expect(typeEnum).toContain('performance');
    });

    it('should handle requirement creation', async () => {
      const requirement = {
        name: 'User Authentication',
        type: 'functional',
        description: 'Users should be able to log in with email and password',
        acceptance_criteria: [
          'Email validation',
          'Password strength requirements',
          'Remember me option'
        ],
        priority: 'high',
        status: 'draft',
        repositories: [
          {
            name: 'backend-api',
            implementation_status: 'not_started',
            branch: 'feat/auth'
          }
        ]
      };

      mockStore.createRequirement.mockResolvedValue({
        id: 'req-123',
        ...requirement,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString()
      });

      // Since we don't have direct access to handler, we'll test via the schema
      const tool = module.tools.find((t: any) => t.name === 'create_requirement');
      expect(tool.inputSchema.properties).toHaveProperty('name');
      expect(tool.inputSchema.properties).toHaveProperty('repositories');
    });
  });

  describe('list_requirements tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'list_requirements');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.properties).toHaveProperty('filter_by_type');
      expect(tool.inputSchema.properties).toHaveProperty('filter_by_status');
      expect(tool.inputSchema.properties).toHaveProperty('filter_by_priority');
    });
  });

  describe('update_requirement tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'update_requirement');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.required).toContain('id');
      expect(tool.inputSchema.properties).toHaveProperty('name');
      expect(tool.inputSchema.properties).toHaveProperty('description');
      expect(tool.inputSchema.properties).toHaveProperty('status');
    });
  });

  describe('link_requirement_to_story tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'link_requirement_to_story');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.required).toContain('requirement_id');
      expect(tool.inputSchema.required).toContain('story_id');
    });
  });

  describe('update_implementation_status tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'update_implementation_status');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.required).toContain('requirement_id');
      expect(tool.inputSchema.required).toContain('repository_name');
      expect(tool.inputSchema.required).toContain('status');
    });

    it('should validate implementation status values', () => {
      const tool = module.tools.find((t: any) => t.name === 'update_implementation_status');
      const statusEnum = tool.inputSchema.properties.status.enum;
      expect(statusEnum).toContain('not_started');
      expect(statusEnum).toContain('in_progress');
      expect(statusEnum).toContain('completed');
      expect(statusEnum).toContain('blocked');
    });
  });

  describe('search_requirements tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'search_requirements');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.required).toContain('query');
      expect(tool.inputSchema.properties).toHaveProperty('search_in');
    });
  });

  describe('generate_requirements_report tool', () => {
    it('should have correct schema', () => {
      const tool = module.tools.find((t: any) => t.name === 'generate_requirements_report');
      expect(tool).toBeDefined();
      expect(tool.inputSchema.properties).toHaveProperty('format');
      expect(tool.inputSchema.properties).toHaveProperty('include_implementation_status');
      expect(tool.inputSchema.properties).toHaveProperty('group_by');
    });
  });
});