/**
 * Task Management Tools
 *
 * Tools for managing tasks, asking questions, and signaling completion.
 */

import { z } from 'zod';
import { defineTool, type ToolResult } from './types.js';

/**
 * Task status enum
 */
export type TaskStatus = 'pending' | 'in_progress' | 'completed';

/**
 * Task interface
 */
export interface Task {
  id: string;
  title: string;
  description: string;
  status: TaskStatus;
}

/**
 * TaskState - Singleton for managing task state
 */
export class TaskState {
  private static instance: TaskState | null = null;

  tasks: Task[] = [];
  completed = false;
  completionSummary: string | null = null;
  pendingQuestion: string | null = null;
  pendingQuestionOptions: string[] | null = null;
  userResponse: string | null = null;
  private nextId = 1;

  private constructor() {}

  /**
   * Get the singleton instance
   */
  static getInstance(): TaskState {
    if (!TaskState.instance) {
      TaskState.instance = new TaskState();
    }
    return TaskState.instance;
  }

  /**
   * Reset the singleton instance
   */
  static reset(): void {
    TaskState.instance = null;
  }

  /**
   * Add a new task
   */
  addTask(title: string, description = ''): Task {
    const task: Task = {
      id: String(this.nextId++),
      title,
      description,
      status: 'pending',
    };
    this.tasks.push(task);
    return task;
  }

  /**
   * Get task by ID
   */
  getTask(taskId: string): Task | undefined {
    return this.tasks.find((t) => t.id === taskId);
  }

  /**
   * Update task status
   */
  updateStatus(taskId: string, status: TaskStatus): boolean {
    const task = this.getTask(taskId);
    if (task) {
      task.status = status;
      return true;
    }
    return false;
  }

  /**
   * Get all tasks
   */
  getAllTasks(): Task[] {
    return [...this.tasks];
  }

  /**
   * Mark overall task as completed
   */
  markCompleted(summary: string): void {
    this.completed = true;
    this.completionSummary = summary;
  }

  /**
   * Set pending question for user
   */
  askQuestion(question: string, options?: string[]): void {
    this.pendingQuestion = question;
    this.pendingQuestionOptions = options ?? null;
    this.userResponse = null;
  }

  /**
   * Set user response to pending question
   */
  setUserResponse(response: string): void {
    this.userResponse = response;
    this.pendingQuestion = null;
    this.pendingQuestionOptions = null;
  }

  /**
   * Check if there's a pending question
   */
  hasPendingQuestion(): boolean {
    return this.pendingQuestion !== null;
  }

  /**
   * Get pending question info
   */
  getPendingQuestion(): { question: string; options: string[] | null } | null {
    if (!this.pendingQuestion) return null;
    return {
      question: this.pendingQuestion,
      options: this.pendingQuestionOptions,
    };
  }
}

/**
 * Get the current task state instance
 */
export function getTaskState(): TaskState {
  return TaskState.getInstance();
}

// ============================================================
// Tool Definitions
// ============================================================

/**
 * WriteTodo Tool
 *
 * Create a new task for tracking work.
 */
export const writeTodoTool = defineTool({
  name: 'write_todo',
  description: 'Create a new task. Use reset=true to clear all existing tasks first.',
  category: 'task',
  schema: z.object({
    title: z.string().min(1).describe('Short task title'),
    description: z.string().optional().describe('Detailed description of what needs to be done'),
    reset: z.boolean().optional().default(false).describe('Set to true to clear all existing tasks before adding this one'),
  }),
  async execute(input): Promise<ToolResult<{
    task: Task;
    totalTasks: number;
    allTasks: Task[];
    wasReset: boolean;
  }>> {
    const { title, description, reset } = input;

    // Reset all tasks if requested
    if (reset) {
      TaskState.reset();
    }

    const state = getTaskState();
    const task = state.addTask(title.trim(), description?.trim() ?? '');

    return {
      success: true,
      data: {
        task,
        totalTasks: state.tasks.length,
        allTasks: state.getAllTasks(),
        wasReset: reset ?? false,
      },
    };
  },
});

/**
 * UpdateTodoList Tool
 *
 * Update task status. Auto-creates tasks if they don't exist.
 */
export const updateTodoListTool = defineTool({
  name: 'update_todo_list',
  description: 'Update task status. Auto-creates tasks if they don\'t exist.',
  category: 'task',
  schema: z.object({
    taskId: z.string().describe('ID of the task to update (e.g., "1", "2")'),
    status: z.enum(['pending', 'in_progress', 'completed']).optional().describe('New status for the task'),
    title: z.string().optional().describe('Task title (used if auto-creating)'),
    description: z.string().optional().describe('Task description (used if auto-creating)'),
  }),
  async execute(input): Promise<ToolResult<{
    taskId: string;
    task: Task;
    allTasks: Task[];
    autoCreated?: boolean;
  }>> {
    const { taskId, status, title, description } = input;
    const state = getTaskState();

    let task = state.getTask(taskId);

    // Auto-create task if not found
    if (!task) {
      const newTask: Task = {
        id: taskId,
        title: title ?? `Task ${taskId}`,
        description: description ?? '',
        status: status ?? 'pending',
      };
      state.tasks.push(newTask);

      return {
        success: true,
        data: {
          taskId,
          task: newTask,
          allTasks: state.getAllTasks(),
          autoCreated: true,
        },
      };
    }

    // Update status if provided
    if (status) {
      task.status = status;
    }

    return {
      success: true,
      data: {
        taskId,
        task,
        allTasks: state.getAllTasks(),
      },
    };
  },
});

/**
 * Choice option for questions
 */
interface ChoiceOption {
  label: string;
  description: string;
}

/**
 * Question with choices
 */
interface ChoiceQuestion {
  question: string;
  header: string;
  options: ChoiceOption[];
  multiSelect: boolean;
}

/**
 * AskChoiceQuestions Tool
 *
 * Ask the user clarifying questions with predefined options.
 * Users can always select "Other" to provide custom input.
 */
export const askChoiceQuestionsTool = defineTool({
  name: 'ask_choice_questions',
  description: `Ask the user clarifying questions with predefined options.

Use this tool when you need to:
1. Gather user preferences or requirements
2. Clarify ambiguous instructions
3. Get decisions on implementation choices
4. Offer choices about what direction to take

Usage notes:
- Users will always be able to select "Other" to provide custom text input
- Use multiSelect: true to allow multiple answers for a question
- If you recommend a specific option, make it first and add "(Recommended)" to label
- Only ask AFTER doing research first (read files, search code, explore)
- Questions should reference actual findings from exploration`,
  category: 'task',
  schema: z.object({
    questions: z.array(z.object({
      question: z.string().min(1).describe('The complete question to ask'),
      header: z.string().max(12).describe('Short label displayed as chip (max 12 chars)'),
      options: z.array(z.object({
        label: z.string().describe('Display text for this option (1-5 words)'),
        description: z.string().describe('Explanation of what this option means'),
      })).min(2).max(4).describe('Available choices (2-4 options)'),
      multiSelect: z.boolean().default(false).describe('Allow multiple selections'),
    })).min(1).max(4).describe('Questions to ask (1-4 questions)'),
  }),
  async execute(input): Promise<ToolResult<{
    questions: ChoiceQuestion[];
    status: string;
    message: string;
  }>> {
    const { questions } = input;
    const state = getTaskState();

    // Store the first question for backward compatibility
    const firstQ = questions[0];
    const optionLabels = firstQ.options.map(o => o.label);
    state.askQuestion(firstQ.question.trim(), optionLabels);

    return {
      success: true,
      data: {
        questions: questions.map(q => ({
          question: q.question.trim(),
          header: q.header,
          options: q.options,
          multiSelect: q.multiSelect,
        })),
        status: 'awaiting_response',
        message: 'Questions will be shown to user. Agent loop will pause.',
      },
    };
  },
});

/**
 * AttemptCompletion Tool
 *
 * Signal task completion with summary.
 */
export const attemptCompletionTool = defineTool({
  name: 'attempt_completion',
  description: 'Signal that the task is complete. Provide a summary of what was accomplished and list files that were modified.',
  category: 'task',
  schema: z.object({
    summary: z.string().min(1).describe('Summary of what was accomplished'),
    filesModified: z.array(z.string()).optional().describe('List of file paths that were modified'),
  }),
  async execute(input): Promise<ToolResult<{
    status: string;
    summary: string;
    filesModified: string[];
    tasksCompleted: string;
    message: string;
  }>> {
    const { summary, filesModified } = input;
    const state = getTaskState();

    state.markCompleted(summary.trim());

    // Count completed vs total tasks
    const completed = state.tasks.filter((t) => t.status === 'completed').length;
    const total = state.tasks.length;

    return {
      success: true,
      data: {
        status: 'completed',
        summary: summary.trim(),
        filesModified: filesModified ?? [],
        tasksCompleted: total > 0 ? `${completed}/${total}` : 'No subtasks',
        message: 'Task marked as complete. Agent loop will terminate.',
      },
    };
  },
});

/**
 * All task management tools
 */
export const taskManagementTools = [
  writeTodoTool,
  updateTodoListTool,
  askChoiceQuestionsTool,
  attemptCompletionTool,
];
