import { describe, it, expect } from 'vitest';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { ConfigManager } from '../../config/config-manager.js';
import { setupAgileManagementTools } from '../../modules/agile-management/index.js';
import { setupKanbanTools } from '../../modules/kanban/index.js';
import { setupDataManagementTools } from '../../modules/data-management/index.js';
import { setupDocumentationTools } from '../../modules/documentation/index.js';
import { setupBusinessGuidanceTools } from '../../modules/business-guidance/index.js';
import { setupProductRoadmap } from '../../modules/product-roadmap/index.js';
import { setupCodeAnalysisTools } from '../../modules/code-analysis/index.js';
import { setupDevelopmentTools } from '../../modules/development/index.js';
import { setupMemoryManagementTools } from '../../modules/memory-management/index.js';
import { setupTestingFrameworkTools } from '../../modules/testing-framework/index.js';

describe('JSON Schema Draft 2020-12 Validation', () => {
  // Create AJV instance with draft 2020-12 support
  const ajv = new Ajv({
    strict: true,
    validateFormats: true,
    allErrors: true,
  });
  
  // Add format validators
  addFormats(ajv);
  
  // Create mock server and config
  const createMocks = () => ({
    server: new Server(
      { name: 'test', version: '1.0.0' }, 
      { capabilities: { tools: {}, resources: {} } }
    ),
    configManager: new ConfigManager()
  });

  const testModuleSchemas = async (moduleName: string, setupFunction: Function) => {
    const { server, configManager } = createMocks();
    const module = await setupFunction(server, configManager);
    
    if (!module.tools || module.tools.length === 0) {
      return;
    }
    
    for (const tool of module.tools) {
      if (tool.inputSchema) {
        // Validate the schema itself is valid JSON Schema
        const schemaSchema = {
          type: 'object',
          properties: {
            type: { type: 'string' },
            properties: { type: 'object' },
            required: { type: 'array', items: { type: 'string' } }
          },
          required: ['type']
        };
        
        const validateSchema = ajv.compile(schemaSchema);
        const schemaValid = validateSchema(tool.inputSchema);
        
        if (!schemaValid) {
          console.error(`Schema validation errors for ${moduleName} - ${tool.name}:`, validateSchema.errors);
        }
        
        expect(schemaValid, `${moduleName} - ${tool.name} schema structure is invalid`).toBe(true);
        
        // Test that the schema can be compiled (validates pattern syntax, etc.)
        try {
          const validate = ajv.compile(tool.inputSchema);
          expect(validate).toBeDefined();
          
          // Test with a sample valid input
          if (tool.inputSchema.properties) {
            const sampleInput: any = {};
            
            // Generate sample data based on schema
            for (const [key, prop] of Object.entries(tool.inputSchema.properties as any)) {
              if (prop.type === 'string') {
                sampleInput[key] = prop.default || 'test';
              } else if (prop.type === 'number') {
                sampleInput[key] = prop.default || 1;
              } else if (prop.type === 'boolean') {
                sampleInput[key] = prop.default || false;
              } else if (prop.type === 'array') {
                sampleInput[key] = prop.default || [];
              } else if (prop.type === 'object') {
                sampleInput[key] = prop.default || {};
              }
            }
            
            // Only include required fields
            if (tool.inputSchema.required && tool.inputSchema.required.length > 0) {
              const requiredInput: any = {};
              for (const field of tool.inputSchema.required) {
                if (sampleInput[field] !== undefined) {
                  requiredInput[field] = sampleInput[field];
                }
              }
              
              const isValid = validate(requiredInput);
              if (!isValid && validate.errors) {
                console.error(`Validation errors for ${moduleName} - ${tool.name}:`, validate.errors);
              }
            }
          }
        } catch (error) {
          throw new Error(`Failed to compile schema for ${moduleName} - ${tool.name}: ${error.message}`);
        }
      }
    }
  };

  it('should validate agile management module schemas', async () => {
    await testModuleSchemas('agile-management', setupAgileManagementTools);
  });

  it('should validate kanban module schemas', async () => {
    await testModuleSchemas('kanban', setupKanbanTools);
  });

  it('should validate data management module schemas', async () => {
    await testModuleSchemas('data-management', setupDataManagementTools);
  });

  it('should validate documentation module schemas', async () => {
    await testModuleSchemas('documentation', setupDocumentationTools);
  });

  it('should validate business guidance module schemas', async () => {
    await testModuleSchemas('business-guidance', setupBusinessGuidanceTools);
  });

  it('should validate product roadmap module schemas', async () => {
    await testModuleSchemas('product-roadmap', setupProductRoadmap);
  });

  it('should validate code analysis module schemas', async () => {
    await testModuleSchemas('code-analysis', setupCodeAnalysisTools);
  });

  it('should validate development module schemas', async () => {
    await testModuleSchemas('development', setupDevelopmentTools);
  });

  it('should validate memory management module schemas', async () => {
    await testModuleSchemas('memory-management', setupMemoryManagementTools);
  });

  it('should validate testing framework module schemas', async () => {
    await testModuleSchemas('testing-framework', setupTestingFrameworkTools);
  });
  
  it('should validate pattern regex syntax', async () => {
    // Test specific patterns that might be problematic
    const testPatterns = [
      { pattern: '^[a-zA-Z0-9 _-]+$', description: 'alphanumeric with space, underscore, hyphen' },
      { pattern: '^[a-zA-Z0-9]+$', description: 'alphanumeric only' },
      { pattern: '^.+$', description: 'any non-empty string' }
    ];
    
    for (const { pattern, description } of testPatterns) {
      const schema = {
        type: 'object',
        properties: {
          name: {
            type: 'string',
            pattern: pattern
          }
        }
      };
      
      try {
        const validate = ajv.compile(schema);
        expect(validate).toBeDefined();
        
        // Test valid inputs based on pattern
        if (pattern === '^[a-zA-Z0-9 _-]+$') {
          // Pattern allows spaces, underscores and hyphens
          expect(validate({ name: 'Test_Name-123' })).toBe(true);
          expect(validate({ name: 'Test Name' })).toBe(true);
        } else if (pattern === '^[a-zA-Z0-9]+$') {
          // Pattern only allows alphanumeric
          expect(validate({ name: 'test123' })).toBe(true);
          expect(validate({ name: 'Test_Name-123' })).toBe(false);
          expect(validate({ name: 'Test Name' })).toBe(false);
        } else if (pattern === '^.+$') {
          // Pattern allows any non-empty string
          expect(validate({ name: 'Any string!' })).toBe(true);
        }
        
        // Test invalid inputs
        expect(validate({ name: '' })).toBe(false);
      } catch (error) {
        throw new Error(`Pattern validation failed for "${description}": ${error.message}`);
      }
    }
  });
});