import { getAuthenticatedClient } from '../../../scripts/utils/directus-client';
import { 
  CreateTask, 
  UpdateTask, 
  TaskResponse, 
  TaskQuery,
  BulkCreateTasks,
  BulkUpdateTasks,
  BulkDeleteTasks,
  DuplicateTask,
  CreateTemplateFromTask,
  ApplyTemplate
} from '../validators/task.validator';

// Import Directus SDK functions with type assertions
const directusSdk = require('@directus/sdk');
const createItem = directusSdk.createItem as any;
const readItems = directusSdk.readItems as any;
const readItem = directusSdk.readItem as any;
const updateItem = directusSdk.updateItem as any;
const deleteItem = directusSdk.deleteItem as any;
const createItems = directusSdk.createItems as any;
const updateItems = directusSdk.updateItems as any;

export class TaskService {
  private client: any;

  constructor() {
    this.initializeClient();
  }

  private async initializeClient() {
    this.client = await getAuthenticatedClient();
  }

  /**
   * Create a single task
   */
  async createTask(data: CreateTask): Promise<TaskResponse> {
    try {
      if (!this.client) await this.initializeClient();
      
      const task = await this.client.request(
        createItem('tasks', {
          ...data,
          created_at: new Date().toISOString(),
          updated_at: new Date().toISOString()
        })
      );
      
      return task;
    } catch (error: any) {
      throw new Error(`Failed to create task: ${error.message}`);
    }
  }

  /**
   * Get all tasks with pagination and filtering
   */
  async getTasks(query: TaskQuery) {
    try {
      if (!this.client) await this.initializeClient();
      
      const { page, limit, sort, filter, search, fields } = query;
      const offset = (page - 1) * limit;
      
      // Build query parameters
      const queryParams: any = {
        limit,
        offset,
        meta: 'total_count'
      };
      
      if (sort) queryParams.sort = sort.split(',');
      if (filter) queryParams.filter = filter;
      if (search) queryParams.search = search;
      if (fields) queryParams.fields = fields;
      
      const response = await this.client.request(
        readItems('tasks', queryParams)
      );
      
      // Calculate pagination metadata
      const totalPages = Math.ceil(response.meta.total_count / limit);
      
      return {
        data: response.data,
        meta: {
          total: response.meta.total_count,
          page,
          limit,
          totalPages
        }
      };
    } catch (error: any) {
      throw new Error(`Failed to fetch tasks: ${error.message}`);
    }
  }

  /**
   * Get a single task by ID
   */
  async getTaskById(id: string): Promise<TaskResponse> {
    try {
      if (!this.client) await this.initializeClient();
      
      const task = await this.client.request(
        readItem('tasks', id)
      );
      
      if (!task) {
        throw new Error('Task not found');
      }
      
      return task;
    } catch (error: any) {
      throw new Error(`Failed to fetch task: ${error.message}`);
    }
  }

  /**
   * Update a task
   */
  async updateTask(id: string, data: UpdateTask): Promise<TaskResponse> {
    try {
      if (!this.client) await this.initializeClient();
      
      const task = await this.client.request(
        updateItem('tasks', id, {
          ...data,
          updated_at: new Date().toISOString()
        })
      );
      
      return task;
    } catch (error: any) {
      throw new Error(`Failed to update task: ${error.message}`);
    }
  }

  /**
   * Delete a task
   */
  async deleteTask(id: string): Promise<void> {
    try {
      if (!this.client) await this.initializeClient();
      
      await this.client.request(
        deleteItem('tasks', id)
      );
    } catch (error: any) {
      throw new Error(`Failed to delete task: ${error.message}`);
    }
  }

  /**
   * Bulk create tasks
   */
  async bulkCreateTasks(data: BulkCreateTasks): Promise<TaskResponse[]> {
    try {
      if (!this.client) await this.initializeClient();
      
      const tasksWithTimestamps = data.tasks.map(task => ({
        ...task,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString()
      }));
      
      const tasks = await this.client.request(
        createItems('tasks', tasksWithTimestamps)
      );
      
      return tasks;
    } catch (error: any) {
      throw new Error(`Failed to bulk create tasks: ${error.message}`);
    }
  }

  /**
   * Bulk update tasks
   */
  async bulkUpdateTasks(data: BulkUpdateTasks): Promise<TaskResponse[]> {
    try {
      if (!this.client) await this.initializeClient();
      
      const updates = data.ids.map(id => ({
        id,
        ...data.updates,
        updated_at: new Date().toISOString()
      }));
      
      const tasks = await this.client.request(
        updateItems('tasks', updates)
      );
      
      return tasks;
    } catch (error: any) {
      throw new Error(`Failed to bulk update tasks: ${error.message}`);
    }
  }

  /**
   * Bulk delete tasks
   */
  async bulkDeleteTasks(data: BulkDeleteTasks): Promise<void> {
    try {
      if (!this.client) await this.initializeClient();
      
      // Delete tasks one by one since deleteItems might not be available
      for (const id of data.ids) {
        await this.client.request(
          deleteItem('tasks', id)
        );
      }
    } catch (error: any) {
      throw new Error(`Failed to bulk delete tasks: ${error.message}`);
    }
  }

  /**
   * Duplicate a task
   */
  async duplicateTask(data: DuplicateTask): Promise<TaskResponse> {
    try {
      if (!this.client) await this.initializeClient();
      
      // Fetch the original task
      const originalTask = await this.getTaskById(data.taskId);
      
      // Remove fields that shouldn't be duplicated
      const { 
        id, 
        created_at, 
        updated_at, 
        created_by,
        actual_hours,
        completed_at,
        ...taskData 
      } = originalTask;
      
      // Apply overrides
      const newTaskData = {
        ...taskData,
        ...data.overrides,
        title: data.overrides?.title || `${taskData.title} (Copy)`,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString()
      };
      
      // Create the duplicated task
      const newTask = await this.client.request(
        createItem('tasks', newTaskData)
      );
      
      // Handle subtasks if requested
      if (data.includeSubtasks) {
        const subtasks = await this.client.request(
          readItems('tasks', {
            filter: {
              parent_task: {
                _eq: data.taskId
              }
            }
          })
        );
        
        if (subtasks.length > 0) {
          const newSubtasks = subtasks.map((subtask: any) => {
            const { id, created_at, updated_at, created_by, ...subtaskData } = subtask;
            return {
              ...subtaskData,
              parent_task: newTask.id,
              created_at: new Date().toISOString(),
              updated_at: new Date().toISOString()
            };
          });
          
          await this.client.request(
            createItems('tasks', newSubtasks)
          );
        }
      }
      
      return newTask;
    } catch (error: any) {
      throw new Error(`Failed to duplicate task: ${error.message}`);
    }
  }

  /**
   * Create a template from a task
   */
  async createTemplateFromTask(data: CreateTemplateFromTask): Promise<any> {
    try {
      if (!this.client) await this.initializeClient();
      
      // Fetch the task
      const task = await this.getTaskById(data.taskId);
      
      // Remove fields that shouldn't be in template
      const excludeDefault = [
        'id', 'created_at', 'updated_at', 'created_by', 
        'actual_hours', 'completed_at', 'progress_percentage',
        ...(data.excludeFields || [])
      ];
      
      const templateData: any = {};
      Object.keys(task).forEach(key => {
        if (!excludeDefault.includes(key)) {
          templateData[key] = task[key as keyof TaskResponse];
        }
      });
      
      // Create template
      const template = await this.client.request(
        createItem('task_templates', {
          name: data.templateName,
          description: data.templateDescription,
          title_template: templateData.title,
          description_template: templateData.description,
          acceptance_criteria_template: templateData.acceptance_criteria,
          default_priority: templateData.priority,
          default_complexity: templateData.complexity,
          estimated_hours: templateData.estimated_hours,
          template_type: 'feature',
          workflow_stage: 'development',
          usage_count: 0,
          created_at: new Date().toISOString(),
          updated_at: new Date().toISOString()
        })
      );
      
      return template;
    } catch (error: any) {
      throw new Error(`Failed to create template from task: ${error.message}`);
    }
  }

  /**
   * Apply a template to create a new task
   */
  async applyTemplate(data: ApplyTemplate): Promise<TaskResponse> {
    try {
      if (!this.client) await this.initializeClient();
      
      // Fetch the template
      const template = await this.client.request(
        readItem('task_templates', data.templateId)
      );
      
      if (!template) {
        throw new Error('Template not found');
      }
      
      // Create task from template
      const taskData = {
        title: template.title_template,
        description: template.description_template,
        acceptance_criteria: template.acceptance_criteria_template,
        priority: template.default_priority,
        complexity: template.default_complexity,
        estimated_hours: template.estimated_hours,
        project: data.projectId,
        ai_generated: true,
        ...data.overrides,
        created_at: new Date().toISOString(),
        updated_at: new Date().toISOString()
      };
      
      const task = await this.client.request(
        createItem('tasks', taskData)
      );
      
      // Update template usage count
      await this.client.request(
        updateItem('task_templates', data.templateId, {
          usage_count: template.usage_count + 1,
          last_used: new Date().toISOString()
        })
      );
      
      return task;
    } catch (error: any) {
      throw new Error(`Failed to apply template: ${error.message}`);
    }
  }
}