import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { CallToolRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js';
import { ConfigManager } from '../../config/config-manager.js';
import { TaskOrchestrator } from './orchestrator.js';
import { OrchestrationStore } from './store.js';
import {
  Task,
  TaskGroup,
  Workflow,
  WorkflowExecution,
  TaskTemplate,
  WorkflowTrigger,
  ScheduleTrigger,
  FileChangeTrigger,
} from './types.js';
import crypto from 'crypto';

let configManager: ConfigManager;
let orchestrator: TaskOrchestrator;
let store: OrchestrationStore;

export async function setupTaskOrchestrationTools(server: Server, config?: ConfigManager): Promise<{ tools: Tool[]; resources: any[] }> {
  configManager = config || new ConfigManager();
  
  orchestrator = new TaskOrchestrator({
    maxConcurrentTasks: 5,
    defaultTimeout: 300000,
    persistence: {
      enabled: true,
      path: '.atlas/orchestration',
    },
  });

  store = new OrchestrationStore('.atlas/orchestration');

  // Set up event listeners
  orchestrator.on('workflow:created', async (workflow) => {
    await store.saveWorkflow(workflow);
  });

  orchestrator.on('execution:completed', async (execution) => {
    await store.saveExecution(execution);
  });

  orchestrator.on('execution:failed', async (execution) => {
    await store.saveExecution(execution);
  });

  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;

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

    switch (name) {
      case 'create_workflow': {
        const { name: workflowName, description, tasks, entryPoint, variables = {} } = args as {
          name: string;
          description?: string;
          tasks: Array<{
            name: string;
            type: Task['type'];
            command?: string;
            dependencies?: string[];
            timeout?: number;
            retries?: number;
          }>;
          entryPoint?: string;
          variables?: Record<string, any>;
        };

        try {
          // Convert input tasks to Task objects
          const workflowTasks: Task[] = tasks.map((task, index) => ({
            id: `task-${index + 1}`,
            name: task.name,
            type: task.type,
            status: 'pending',
            dependencies: task.dependencies || [],
            input: task.type === 'command' ? { command: task.command } : undefined,
            retries: 0,
            maxRetries: task.retries || 3,
            timeout: task.timeout,
          }));

          const workflow = await orchestrator.createWorkflow({
            name: workflowName,
            description,
            version: '1.0.0',
            tasks: workflowTasks,
            groups: [],
            entryPoint: entryPoint || workflowTasks[0]?.id || '',
            variables,
            status: 'active',
          });

          let output = `✅ Workflow created\n\n`;
          output += `**ID**: ${workflow.id}\n`;
          output += `**Name**: ${workflow.name}\n`;
          output += `**Tasks**: ${workflow.tasks.length}\n`;
          output += `**Status**: ${workflow.status}\n\n`;
          
          output += `**Task Graph**:\n`;
          workflow.tasks.forEach(task => {
            output += `• ${task.name} (${task.id})`;
            if (task.dependencies.length > 0) {
              output += ` → depends on: ${task.dependencies.join(', ')}`;
            }
            output += '\n';
          });

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              workflow,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to create workflow\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'execute_workflow': {
        const { workflowId, variables = {} } = args as {
          workflowId: string;
          variables?: Record<string, any>;
        };

        try {
          const execution = await orchestrator.executeWorkflow(workflowId, variables);
          
          let output = `🚀 Workflow execution ${execution.status}\n\n`;
          output += `**Execution ID**: ${execution.id}\n`;
          output += `**Workflow**: ${execution.workflowId}\n`;
          output += `**Status**: ${execution.status}\n`;
          output += `**Duration**: ${execution.duration ? `${(execution.duration / 1000).toFixed(2)}s` : 'N/A'}\n\n`;
          
          output += `**Task Results**:\n`;
          execution.tasks.forEach(task => {
            const icon = task.status === 'completed' ? '✅' : 
                        task.status === 'failed' ? '❌' : 
                        task.status === 'skipped' ? '⏭️' : '🔄';
            output += `${icon} ${task.taskId} - ${task.status}`;
            if (task.duration) {
              output += ` (${(task.duration / 1000).toFixed(2)}s)`;
            }
            if (task.error) {
              output += `\n   Error: ${task.error}`;
            }
            output += '\n';
          });

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              execution,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Workflow execution failed\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              workflowId,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'list_workflows': {
        const { status } = args as { status?: Workflow['status'] };

        try {
          const workflows = orchestrator.listWorkflows();
          const filteredWorkflows = status 
            ? workflows.filter(w => w.status === status)
            : workflows;

          let output = `📋 Workflows (${filteredWorkflows.length})\n\n`;
          
          if (filteredWorkflows.length === 0) {
            output += 'No workflows found.';
          } else {
            filteredWorkflows.forEach(workflow => {
              const icon = workflow.status === 'active' ? '🟢' : 
                          workflow.status === 'completed' ? '✅' : 
                          workflow.status === 'failed' ? '❌' : '⏸️';
              output += `${icon} **${workflow.name}** (${workflow.id})\n`;
              output += `   Status: ${workflow.status}\n`;
              output += `   Tasks: ${workflow.tasks.length}\n`;
              output += `   Created: ${new Date(workflow.createdAt).toLocaleDateString()}\n\n`;
            });
          }

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              workflows: filteredWorkflows,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to list workflows\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'get_execution_status': {
        const { executionId } = args as { executionId: string };

        try {
          const execution = orchestrator.getExecutionStatus(executionId);
          
          if (!execution) {
            throw new Error(`Execution ${executionId} not found`);
          }

          let output = `📊 Execution Status\n\n`;
          output += `**ID**: ${execution.id}\n`;
          output += `**Workflow**: ${execution.workflowId}\n`;
          output += `**Status**: ${execution.status}\n`;
          output += `**Started**: ${new Date(execution.startTime).toLocaleString()}\n`;
          
          if (execution.endTime) {
            output += `**Ended**: ${new Date(execution.endTime).toLocaleString()}\n`;
            output += `**Duration**: ${((execution.duration || 0) / 1000).toFixed(2)}s\n`;
          }
          
          output += `\n**Tasks** (${execution.tasks.length}):\n`;
          execution.tasks.forEach(task => {
            const icon = task.status === 'completed' ? '✅' : 
                        task.status === 'failed' ? '❌' : 
                        task.status === 'running' ? '🔄' : 
                        task.status === 'skipped' ? '⏭️' : '⏳';
            output += `${icon} ${task.taskId} - ${task.status}`;
            if (task.duration) {
              output += ` (${(task.duration / 1000).toFixed(2)}s)`;
            }
            output += '\n';
            
            if (task.error) {
              output += `   ❌ Error: ${task.error}\n`;
            }
          });
          
          if (execution.error) {
            output += `\n❌ **Execution Error**: ${execution.error}`;
          }

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              execution,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to get execution status\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              executionId,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'cancel_execution': {
        const { executionId } = args as { executionId: string };

        try {
          await orchestrator.cancelExecution(executionId);

          return {
            content: [
              {
                type: 'text',
                text: `✅ Execution cancelled\n\n**Execution ID**: ${executionId}\n\nThe workflow execution has been cancelled. Running tasks have been stopped.`,
              },
            ],
            structured: {
              executionId,
              cancelled: true,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to cancel execution\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              executionId,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'create_task_template': {
        const { name: templateName, description, category, type, defaultConfig, parameters = [] } = args as {
          name: string;
          description: string;
          category: TaskTemplate['category'];
          type: Task['type'];
          defaultConfig?: Partial<Task>;
          parameters?: TaskTemplate['parameters'];
        };

        try {
          const template: TaskTemplate = {
            id: crypto.randomUUID(),
            name: templateName,
            description,
            category,
            type,
            defaultConfig: defaultConfig || {},
            parameters,
            tags: [],
          };

          await store.saveTemplate(template);

          return {
            content: [
              {
                type: 'text',
                text: `✅ Task template created\n\n**Name**: ${template.name}\n**Category**: ${template.category}\n**Type**: ${template.type}\n**Parameters**: ${template.parameters.length}\n\nTemplate saved successfully. You can now use this template when creating tasks.`,
              },
            ],
            structured: {
              template,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to create task template\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'list_task_templates': {
        const { category } = args as { category?: TaskTemplate['category'] };

        try {
          const templates = await store.listTemplates(category);

          let output = `📋 Task Templates`;
          if (category) {
            output += ` (${category})`;
          }
          output += ` - ${templates.length} found\n\n`;

          if (templates.length === 0) {
            output += 'No templates found.';
          } else {
            const grouped = templates.reduce((acc, template) => {
              if (!acc[template.category]) {
                acc[template.category] = [];
              }
              acc[template.category].push(template);
              return acc;
            }, {} as Record<string, TaskTemplate[]>);

            Object.entries(grouped).forEach(([cat, temps]) => {
              output += `**${cat.charAt(0).toUpperCase() + cat.slice(1)}**\n`;
              temps.forEach(template => {
                output += `• ${template.name} - ${template.description}\n`;
                output += `  Type: ${template.type}, Parameters: ${template.parameters.length}\n`;
              });
              output += '\n';
            });
          }

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              templates,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to list task templates\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'get_workflow_metrics': {
        const { workflowId } = args as { workflowId: string };

        try {
          const metrics = await store.getWorkflowMetrics(workflowId);

          let output = `📈 Workflow Metrics\n\n`;
          output += `**Total Runs**: ${metrics.totalRuns}\n`;
          output += `**Successful**: ${metrics.successfulRuns} (${((metrics.successfulRuns / metrics.totalRuns) * 100).toFixed(1)}%)\n`;
          output += `**Failed**: ${metrics.failedRuns} (${((metrics.failedRuns / metrics.totalRuns) * 100).toFixed(1)}%)\n`;
          output += `**Average Duration**: ${(metrics.averageDuration / 1000).toFixed(2)}s\n\n`;

          if (Object.keys(metrics.taskMetrics).length > 0) {
            output += `**Task Performance**:\n`;
            Object.entries(metrics.taskMetrics).forEach(([taskId, taskMetric]) => {
              output += `• ${taskId}\n`;
              output += `  Success Rate: ${((taskMetric.successfulExecutions / taskMetric.totalExecutions) * 100).toFixed(1)}%\n`;
              output += `  Avg Duration: ${(taskMetric.averageDuration / 1000).toFixed(2)}s\n`;
            });
          }

          if (Object.keys(metrics.popularTriggers).length > 0) {
            output += `\n**Triggers**:\n`;
            Object.entries(metrics.popularTriggers)
              .sort((a, b) => b[1] - a[1])
              .forEach(([trigger, count]) => {
                output += `• ${trigger}: ${count} times\n`;
              });
          }

          return {
            content: [
              {
                type: 'text',
                text: output,
              },
            ],
            structured: {
              metrics,
              workflowId,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to get workflow metrics\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              workflowId,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      case 'complete_manual_task': {
        const { taskId, output, error } = args as {
          taskId: string;
          output?: any;
          error?: string;
        };

        try {
          orchestrator.completeManualTask(taskId, output, error);

          return {
            content: [
              {
                type: 'text',
                text: `✅ Manual task completed\n\n**Task ID**: ${taskId}\n**Status**: ${error ? 'Failed' : 'Completed'}\n\nThe manual task has been marked as complete.`,
              },
            ],
            structured: {
              taskId,
              completed: true,
              error,
              timestamp: new Date().toISOString(),
            },
          };
        } catch (error: any) {
          return {
            content: [
              {
                type: 'text',
                text: `❌ Failed to complete manual task\n\n**Error**: ${error.message}`,
              },
            ],
            structured: {
              error: error.message,
              taskId,
              timestamp: new Date().toISOString(),
            },
          };
        }
      }

      default:
        return null as any;
    }
  });

  return {
    tools: [
      {
        name: 'create_workflow',
        description: 'Create a new task workflow with dependencies',
        inputSchema: {
          type: 'object',
          properties: {
            name: { type: 'string', description: 'Workflow name' },
            description: { type: 'string', description: 'Workflow description' },
            tasks: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  name: { type: 'string', description: 'Task name' },
                  type: {
                    type: 'string',
                    enum: ['command', 'function', 'manual', 'parallel', 'sequential'],
                    description: 'Task type',
                  },
                  command: { type: 'string', description: 'Command to execute (for command type)' },
                  dependencies: {
                    type: 'array',
                    items: { type: 'string' },
                    description: 'Task names this task depends on',
                  },
                  timeout: { type: 'number', description: 'Timeout in milliseconds' },
                  retries: { type: 'number', description: 'Maximum retry attempts', default: 3 },
                },
                required: ['name', 'type'],
              },
              description: 'Workflow tasks',
            },
            entryPoint: { type: 'string', description: 'Entry task name' },
            variables: {
              type: 'object',
              description: 'Workflow variables',
            },
          },
          required: ['name', 'tasks'],
        },
      },
      {
        name: 'execute_workflow',
        description: 'Execute a workflow with optional variables',
        inputSchema: {
          type: 'object',
          properties: {
            workflowId: { type: 'string', description: 'Workflow ID to execute' },
            variables: {
              type: 'object',
              description: 'Variables to pass to the workflow',
            },
          },
          required: ['workflowId'],
        },
      },
      {
        name: 'list_workflows',
        description: 'List all workflows',
        inputSchema: {
          type: 'object',
          properties: {
            status: {
              type: 'string',
              enum: ['draft', 'active', 'completed', 'failed', 'cancelled'],
              description: 'Filter by status',
            },
          },
          required: [],
        },
      },
      {
        name: 'get_execution_status',
        description: 'Get the status of a workflow execution',
        inputSchema: {
          type: 'object',
          properties: {
            executionId: { type: 'string', description: 'Execution ID' },
          },
          required: ['executionId'],
        },
      },
      {
        name: 'cancel_execution',
        description: 'Cancel a running workflow execution',
        inputSchema: {
          type: 'object',
          properties: {
            executionId: { type: 'string', description: 'Execution ID to cancel' },
          },
          required: ['executionId'],
        },
      },
      {
        name: 'create_task_template',
        description: 'Create a reusable task template',
        inputSchema: {
          type: 'object',
          properties: {
            name: { type: 'string', description: 'Template name' },
            description: { type: 'string', description: 'Template description' },
            category: {
              type: 'string',
              enum: ['development', 'testing', 'deployment', 'maintenance', 'custom'],
              description: 'Template category',
            },
            type: {
              type: 'string',
              enum: ['command', 'function', 'manual', 'parallel', 'sequential'],
              description: 'Task type',
            },
            defaultConfig: {
              type: 'object',
              description: 'Default task configuration',
            },
            parameters: {
              type: 'array',
              items: {
                type: 'object',
                properties: {
                  name: { type: 'string' },
                  type: { type: 'string', enum: ['string', 'number', 'boolean', 'array', 'object'] },
                  description: { type: 'string' },
                  required: { type: 'boolean' },
                  default: {},
                },
                required: ['name', 'type', 'required'],
              },
              description: 'Template parameters',
            },
          },
          required: ['name', 'description', 'category', 'type'],
        },
      },
      {
        name: 'list_task_templates',
        description: 'List available task templates',
        inputSchema: {
          type: 'object',
          properties: {
            category: {
              type: 'string',
              enum: ['development', 'testing', 'deployment', 'maintenance', 'custom'],
              description: 'Filter by category',
            },
          },
          required: [],
        },
      },
      {
        name: 'get_workflow_metrics',
        description: 'Get execution metrics for a workflow',
        inputSchema: {
          type: 'object',
          properties: {
            workflowId: { type: 'string', description: 'Workflow ID' },
          },
          required: ['workflowId'],
        },
      },
      {
        name: 'complete_manual_task',
        description: 'Mark a manual task as complete',
        inputSchema: {
          type: 'object',
          properties: {
            taskId: { type: 'string', description: 'Task ID' },
            output: { description: 'Task output data' },
            error: { type: 'string', description: 'Error message if task failed' },
          },
          required: ['taskId'],
        },
      },
    ],
    resources: [],
  };
}