import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { ConfigManager } from '../../config/config-manager.js';
import { ElicitationManager } from '../../utils/elicitation-manager.js';
import { ProjectTemplate, ProjectConfig } from './types.js';
import { ProjectTemplates } from './templates.js';
import { promises as fs } from 'fs';
import path from 'path';

let configManager: ConfigManager;
let elicitationManager: ElicitationManager;

export async function setupProjectInitTools(server: Server, config?: ConfigManager) {
  configManager = config || new ConfigManager();
  elicitationManager = new ElicitationManager();
  
  // Register elicitation flows
  elicitationManager.registerFlow(ElicitationManager.createProjectSetupFlow());
  elicitationManager.registerFlow(ElicitationManager.createFeatureFlow());

  // Add project initialization tool handlers
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;

    if (!args) {
      throw new Error('No arguments provided');
    }

    switch (name) {
      case 'init_project_interactive': {
        // This is a special tool that uses elicitation
        return {
          content: [
            {
              type: 'text',
              text: `🚀 Starting interactive project setup...\n\nI'll ask you a few questions to configure your project perfectly.`,
            },
          ],
          elicitation: {
            flow: 'project_setup',
            onComplete: 'init_project',
          },
        };
      }
      
      case 'init_project': {
        const { 
          projectName, 
          projectType, 
          includeClaudeConfig = true, 
          answers,
          createNewDirectory = false
        } = args as {
          projectName: string;
          projectType: string;
          includeClaudeConfig?: boolean;
          answers?: Record<string, any>;
          createNewDirectory?: boolean;
        };
        
        // Use answers from elicitation if available
        const config: ProjectConfig = {
          name: projectName,
          type: answers?.projectType || projectType,
          language: answers?.language || 'typescript',
          testFramework: answers?.testFramework,
          features: {
            tdd: answers?.tddMode !== 'off',
            git: true,
            ci: true,
            docker: false,
            linting: true,
          },
        };
        
        // Determine project path - current directory by default
        const projectPath = createNewDirectory 
          ? path.join(process.cwd(), projectName)
          : process.cwd();
          
        // If using current directory, validate it's safe
        if (!createNewDirectory) {
          const storageManager = configManager.getStorageManager();
          try {
            storageManager.validateNotInAtlasRepo();
          } catch (error) {
            return {
              content: [
                {
                  type: 'text',
                  text: `❌ Cannot initialize project in Atlas MCP repository!\n\n` +
                        `Please run this command from your project directory, or use createNewDirectory: true`,
                },
              ],
            };
          }
        }
        
        await createProjectStructure(projectPath, config, !createNewDirectory);
        
        // Set up Atlas configuration
        const atlasConfig = {
          projectMode: 'new' as const,
          projectName,
          features: {
            tddEnforcement: answers?.tddMode || 'strict',
            autoInit: true,
          },
        };
        
        configManager.set(atlasConfig);
        await configManager.save();
        
        return {
          content: [
            {
              type: 'text',
              text: `✅ Project "${projectName}" initialized successfully!\n\n` +
                    `📁 Location: ${projectPath}\n` +
                    `🔧 Type: ${config.type}\n` +
                    `💻 Language: ${config.language}\n` +
                    `🧪 Test Framework: ${config.testFramework || 'none'}\n` +
                    `🚦 TDD Mode: ${atlasConfig.features.tddEnforcement}\n\n` +
                    `Next steps:\n` +
                    (createNewDirectory ? `1. cd ${projectName}\n` : '') +
                    `${createNewDirectory ? '2' : '1'}. npm install (or equivalent)\n` +
                    `${createNewDirectory ? '3' : '2'}. Start building with TDD!`,
            },
          ],
          structured: {
            project: {
              name: projectName,
              path: projectPath,
              type: config.type,
              language: config.language,
              created: new Date().toISOString(),
            },
            config: atlasConfig,
          },
        };
      }
      
      case 'create_feature_interactive': {
        return {
          content: [
            {
              type: 'text',
              text: `📋 Let's plan your new feature...\n\nI'll help you set up a proper TDD workflow.`,
            },
          ],
          elicitation: {
            flow: 'new_feature',
            onComplete: 'create_feature',
          },
        };
      }
      
      case 'list_project_templates': {
        const templates = ProjectTemplates.getAllTemplates();
        
        const templateList = templates.map(t => 
          `📋 **${t.name}** (${t.type})\n   ${t.description}\n   Files: ${t.files.length} | Dependencies: ${t.dependencies.length + t.devDependencies.length}`
        ).join('\n\n');
        
        return {
          content: [
            {
              type: 'text',
              text: `📚 Available Project Templates\n\n${templateList}\n\nUse generate_project_from_template to create from template.`,
            },
          ],
          structured: {
            templates: templates.map(t => ({
              name: t.name,
              type: t.type,
              description: t.description,
              fileCount: t.files.length,
              dependencyCount: t.dependencies.length + t.devDependencies.length,
            })),
          },
        };
      }
      
      case 'generate_project_from_template': {
        const { templateType, projectName, customConfig = {} } = args as {
          templateType: string;
          projectName: string;
          customConfig?: Partial<ProjectConfig>;
        };
        
        const template = ProjectTemplates.getTemplate(templateType);
        if (!template) {
          const available = ProjectTemplates.getAllTemplates().map(t => t.type);
          return {
            content: [
              {
                type: 'text',
                text: `❌ Template type "${templateType}" not found.\n\nAvailable types: ${available.join(', ')}`,
              },
            ],
          };
        }
        
        const projectPath = process.cwd();
        const storageManager = configManager.getStorageManager();
        
        try {
          // Validate not in Atlas repo
          storageManager.validateNotInAtlasRepo();
          
          const config: ProjectConfig = {
            name: projectName,
            type: templateType,
            description: customConfig.description || template.description,
            language: 'typescript',
            author: customConfig.author,
            license: customConfig.license || 'MIT',
            ...customConfig,
            features: {
              tdd: true,
              git: true,
              ci: true,
              docker: false,
              linting: true,
              ...customConfig.features,
            },
          };
          
          await createProjectFromTemplate(projectPath, config, template);
          
          return {
            content: [
              {
                type: 'text',
                text: `✅ Project created from ${template.name} template!\n\n` +
                      `📋 Project: ${projectName}\n` +
                      `📁 Location: ${projectPath}\n` +
                      `📄 Files created: ${template.files.length}\n` +
                      `📦 Dependencies: ${template.dependencies.length + template.devDependencies.length}\n\n` +
                      `Next steps:\n${template.postInitSteps.map((step, i) => `${i + 1}. ${step}`).join('\n')}`,
              },
            ],
            structured: {
              project: {
                name: projectName,
                path: projectPath,
                template: template.name,
                type: templateType,
              },
              template: {
                name: template.name,
                filesCreated: template.files.length,
                dependencies: template.dependencies.length + template.devDependencies.length,
              },
            },
          };
        } catch (error) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Error creating project: ${(error as Error).message}`,
              },
            ],
          };
        }
      }
      
      default:
        // Not a project init tool
        return null as any;
    }
  });

  return {
    tools: [
      {
        name: 'init_project_interactive',
        description: 'Initialize a new project with interactive setup',
        inputSchema: {
          type: 'object',
          properties: {},
          required: []
        },
      },
      {
        name: 'init_project',
        description: 'Initialize a new startup project with best practices',
        inputSchema: {
          type: 'object',
          properties: {
            projectName: { type: 'string', description: 'Name of the project' },
            projectType: { 
              type: 'string', 
              enum: ['library', 'api', 'web-app', 'cli-tool', 'saas', 'marketplace', 'ai-tool', 'mobile-app', 'other'],
              description: 'Type of project' 
            },
            includeClaudeConfig: { type: 'boolean', default: true },
            createNewDirectory: { 
              type: 'boolean', 
              default: false,
              description: 'Create a new directory for the project (default: use current directory)'
            },
            answers: { 
              type: 'object',
              description: 'Answers from elicitation flow',
              additionalProperties: true,
            },
          },
          required: ['projectName', 'projectType'],
        },
        outputSchema: {
          type: 'object',
          properties: {
            project: {
              type: 'object',
              properties: {
                name: { type: 'string' },
                path: { type: 'string' },
                type: { type: 'string' },
                language: { type: 'string' },
                created: { type: 'string', format: 'date-time' },
              },
            },
            config: { type: 'object' },
          },
        },
      },
      {
        name: 'create_feature_interactive',
        description: 'Plan a new feature with interactive TDD setup',
        inputSchema: {
          type: 'object',
          properties: {},
          required: []
        },
      },
      {
        name: 'list_project_templates',
        description: 'List all available project templates',
        inputSchema: {
          type: 'object',
          properties: {},
          required: []
        },
      },
      {
        name: 'generate_project_from_template',
        description: 'Generate a project from a specific template',
        inputSchema: {
          type: 'object',
          properties: {
            templateType: { 
              type: 'string', 
              enum: ['library', 'api', 'web-app', 'cli-tool'],
              description: 'Template type to use' 
            },
            projectName: { type: 'string', description: 'Name of the project' },
            customConfig: { 
              type: 'object',
              description: 'Custom configuration options',
              additionalProperties: true,
            },
          },
          required: ['templateType', 'projectName'],
        },
      },
    ],
    resources: [],
  };
}

async function createProjectFromTemplate(projectPath: string, config: ProjectConfig, template: any): Promise<void> {
  // Generate template variables
  const variables = ProjectTemplates.generateVariables(config);
  
  // Create all template files
  for (const file of template.files) {
    const filePath = path.join(projectPath, file.path);
    await fs.mkdir(path.dirname(filePath), { recursive: true });
    
    let content = file.content;
    if (file.isTemplate) {
      content = ProjectTemplates.processTemplate(content, variables);
    }
    
    await fs.writeFile(filePath, content, 'utf-8');
  }
  
  // Create package.json if it's a Node.js project
  if (template.dependencies || template.devDependencies) {
    const packageJson = {
      name: variables.kebabName,
      version: '1.0.0',
      description: config.description || template.description,
      scripts: template.scripts,
      dependencies: template.dependencies.reduce((acc: any, dep: string) => {
        acc[dep] = 'latest';
        return acc;
      }, {}),
      devDependencies: template.devDependencies.reduce((acc: any, dep: string) => {
        acc[dep] = 'latest';
        return acc;
      }, {}),
      keywords: [config.type],
      author: config.author || '',
      license: config.license || 'MIT',
    };
    
    await fs.writeFile(
      path.join(projectPath, 'package.json'),
      JSON.stringify(packageJson, null, 2)
    );
  }
  
  // Create .gitignore
  if (config.features?.git) {
    const gitignoreEntries = [
      'node_modules/',
      '*.log',
      '.DS_Store',
      '.env',
      '.env.local',
      '.atlas/',
      ...template.gitignoreEntries,
    ];
    
    await fs.writeFile(
      path.join(projectPath, '.gitignore'),
      gitignoreEntries.join('\n')
    );
  }
  
  // Create README if not already created by template
  const readmePath = path.join(projectPath, 'README.md');
  try {
    await fs.access(readmePath);
  } catch {
    const readme = `# ${config.name}\n\n${config.description || template.description}\n\n## Getting Started\n\n${template.postInitSteps.map(step => `- ${step}`).join('\n')}\n`;
    await fs.writeFile(readmePath, readme);
  }
}

async function createProjectStructure(projectPath: string, config: ProjectConfig, useExisting: boolean = false): Promise<void> {
  // Create base directory only if needed
  if (!useExisting) {
    await fs.mkdir(projectPath, { recursive: true });
  }
  
  // Create common directories
  const dirs = ['src', 'tests', 'docs'];
  if (config.features.ci) dirs.push('.github/workflows');
  
  for (const dir of dirs) {
    await fs.mkdir(path.join(projectPath, dir), { recursive: true });
  }
  
  // Create package.json for Node projects
  if (['typescript', 'javascript'].includes(config.language)) {
    const packageJson = {
      name: config.name,
      version: '0.1.0',
      description: config.description || 'A new project',
      main: 'src/index.' + (config.language === 'typescript' ? 'ts' : 'js'),
      scripts: {
        test: config.testFramework === 'jest' ? 'jest' : 'echo "No tests yet"',
        dev: config.language === 'typescript' ? 'tsx src/index.ts' : 'node src/index.js',
        build: config.language === 'typescript' ? 'tsc' : 'echo "No build needed"',
      },
      keywords: [],
      author: config.author || '',
      license: config.license || 'MIT',
    };
    
    await fs.writeFile(
      path.join(projectPath, 'package.json'),
      JSON.stringify(packageJson, null, 2)
    );
  }
  
  // Create .gitignore
  if (config.features.git) {
    const gitignore = [
      'node_modules/',
      'dist/',
      '.env',
      '.env.local',
      '*.log',
      '.DS_Store',
      'coverage/',
      '.atlas/',
    ].join('\n');
    
    await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
  }
  
  // Create README
  const readme = `# ${config.name}\n\n${config.description || 'A new project built with Atlas MCP'}\n\n## Getting Started\n\n### Development\n\nThis project uses Test-Driven Development (TDD). Always write tests first!\n\n### Testing\n\n\`\`\`bash\nnpm test\n\`\`\`\n`;
  
  await fs.writeFile(path.join(projectPath, 'README.md'), readme);
  
  // Create CLAUDE.md if requested
  const claudeMd = `# Claude Code Configuration\n\nThis project uses Atlas MCP for project management.\n\n## TDD Workflow\n\n1. Always write tests before implementation\n2. Run tests to see them fail (RED)\n3. Write minimal code to pass (GREEN)\n4. Refactor while keeping tests green\n\n## Available Tools\n\n- \`create_feature\`: Start a new feature with TDD\n- \`write_test\`: Write a new test case\n- \`run_tests\`: Execute the test suite\n`;
  
  await fs.writeFile(path.join(projectPath, 'CLAUDE.md'), claudeMd);
}