'use strict';

const taskRepository = require('../../tasks/repository');
const {
    serializeTask,
    serializeTasks,
} = require('../../tasks/core/serializers');
const { buildTaskAttributes } = require('../../tasks/core/builders');
const { Op } = require('sequelize');
const { Task, Project, Tag } = require('../../../models');

/**
 * Helper to find task by ID or UID
 */
async function findTaskByIdentifier(identifier, userId) {
    const isNumeric = !isNaN(identifier);

    if (isNumeric) {
        return await taskRepository.findByIdAndUser(
            parseInt(identifier),
            userId,
            {
                include: [
                    { model: Project, as: 'Project' },
                    { model: Tag, as: 'Tags' },
                ],
            }
        );
    } else {
        return await taskRepository.findByUid(identifier, {
            include: [
                { model: Project, as: 'Project' },
                { model: Tag, as: 'Tags' },
            ],
        });
    }
}

/**
 * Register all task-related MCP tools
 */
function registerTaskTools(server, context, tools) {
    // 1. list_tasks - List tasks with filtering
    tools.push({
        name: 'list_tasks',
        description: 'List tasks from tududi with optional filtering',
        inputSchema: {
            type: 'object',
            properties: {
                type: {
                    type: 'string',
                    enum: ['today', 'upcoming', 'completed', 'archived', 'all'],
                    description: 'Filter tasks by type',
                },
                status: {
                    type: 'string',
                    enum: ['pending', 'in_progress', 'completed', 'archived'],
                    description: 'Filter by status',
                },
                project_id: {
                    type: 'number',
                    description: 'Filter by project ID',
                },
                limit: {
                    type: 'number',
                    description: 'Maximum number of tasks to return',
                    default: 50,
                },
            },
        },
        handler: async (params) => {
            const where = { user_id: context.userId };
            const limit = params.limit || 50;

            // Apply status filter
            if (params.status) {
                const statusMap = {
                    pending: 0,
                    in_progress: 1,
                    completed: 2,
                    archived: 6,
                };
                where.status = statusMap[params.status];
            }

            // Apply project filter
            if (params.project_id) {
                where.project_id = params.project_id;
            }

            // Apply type filter
            if (params.type === 'completed') {
                where.status = 2;
            } else if (params.type === 'archived') {
                where.status = 6;
            } else if (params.type === 'today' || params.type === 'upcoming') {
                where.status = { [Op.ne]: 6 }; // Not archived
            }

            const tasks = await taskRepository.findAll(where, {
                include: [
                    { model: Project, as: 'Project' },
                    { model: Tag, as: 'Tags' },
                ],
                limit: limit,
                order: [['created_at', 'DESC']],
            });

            const serializedTasks = await serializeTasks(
                tasks,
                context.user.timezone
            );

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                count: serializedTasks.length,
                                tasks: serializedTasks,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 2. get_task - Get single task by ID or UID
    tools.push({
        name: 'get_task',
        description: 'Get a specific task by ID or UID with full details',
        inputSchema: {
            type: 'object',
            properties: {
                id: {
                    type: ['number', 'string'],
                    description: 'Task ID (number) or UID (string)',
                },
            },
            required: ['id'],
        },
        handler: async (params) => {
            const task = await findTaskByIdentifier(params.id, context.userId);

            if (!task) {
                throw new Error(`Task not found: ${params.id}`);
            }

            // Check ownership
            if (task.user_id !== context.userId) {
                throw new Error('Access denied');
            }

            const serialized = await serializeTask(task, context.user.timezone);

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(serialized, null, 2),
                    },
                ],
            };
        },
    });

    // 3. create_task - Create new task
    tools.push({
        name: 'create_task',
        description: 'Create a new task in tududi',
        inputSchema: {
            type: 'object',
            properties: {
                name: {
                    type: 'string',
                    description: 'Task name (required)',
                },
                description: {
                    type: 'string',
                    description: 'Task description/note',
                },
                priority: {
                    type: 'string',
                    enum: ['low', 'medium', 'high'],
                    description: 'Task priority',
                },
                due_date: {
                    type: 'string',
                    description: 'Due date (ISO 8601 format)',
                },
                project_id: {
                    type: 'number',
                    description: 'Project ID to assign task to',
                },
                tags: {
                    type: 'array',
                    items: { type: 'string' },
                    description: 'Array of tag names',
                },
            },
            required: ['name'],
        },
        handler: async (params) => {
            const priorityMap = { low: 0, medium: 1, high: 2 };

            const taskData = {
                user_id: context.userId,
                name: params.name,
                note: params.description || '',
                priority: params.priority ? priorityMap[params.priority] : 1,
                status: 0, // pending
                due_date: params.due_date || null,
                project_id: params.project_id || null,
            };

            const task = await taskRepository.create(taskData);

            // Handle tags if provided
            if (params.tags && params.tags.length > 0) {
                const tagInstances = await Promise.all(
                    params.tags.map(async (tagName) => {
                        const [tag] = await Tag.findOrCreate({
                            where: { name: tagName, user_id: context.userId },
                        });
                        return tag;
                    })
                );
                await task.setTags(tagInstances);
            }

            // Reload with associations
            const reloadedTask = await taskRepository.findByIdAndUser(
                task.id,
                context.userId,
                {
                    include: [
                        { model: Project, as: 'Project' },
                        { model: Tag, as: 'Tags' },
                    ],
                }
            );

            const serialized = await serializeTask(
                reloadedTask,
                context.user.timezone
            );

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                message: 'Task created successfully',
                                task: serialized,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 4. update_task - Update existing task
    tools.push({
        name: 'update_task',
        description: 'Update an existing task',
        inputSchema: {
            type: 'object',
            properties: {
                id: {
                    type: ['number', 'string'],
                    description: 'Task ID or UID',
                },
                name: { type: 'string', description: 'New task name' },
                description: { type: 'string', description: 'New description' },
                priority: {
                    type: 'string',
                    enum: ['low', 'medium', 'high'],
                },
                status: {
                    type: 'string',
                    enum: ['pending', 'in_progress', 'completed', 'archived'],
                },
                due_date: { type: 'string', description: 'New due date' },
                today: {
                    type: 'boolean',
                    description: 'Add to Today list',
                },
            },
            required: ['id'],
        },
        handler: async (params) => {
            const task = await findTaskByIdentifier(params.id, context.userId);

            if (!task) {
                throw new Error(`Task not found: ${params.id}`);
            }

            if (task.user_id !== context.userId) {
                throw new Error('Access denied');
            }

            const updates = {};
            if (params.name !== undefined) updates.name = params.name;
            if (params.description !== undefined)
                updates.note = params.description;
            if (params.priority) {
                const priorityMap = { low: 0, medium: 1, high: 2 };
                updates.priority = priorityMap[params.priority];
            }
            if (params.status) {
                const statusMap = {
                    pending: 0,
                    in_progress: 1,
                    completed: 2,
                    archived: 6,
                };
                updates.status = statusMap[params.status];
            }
            if (params.due_date !== undefined)
                updates.due_date = params.due_date;
            if (params.today !== undefined) updates.today = params.today;

            await task.update(updates);

            // Reload with associations
            const reloadedTask = await taskRepository.findByIdAndUser(
                task.id,
                context.userId,
                {
                    include: [
                        { model: Project, as: 'Project' },
                        { model: Tag, as: 'Tags' },
                    ],
                }
            );

            const serialized = await serializeTask(
                reloadedTask,
                context.user.timezone
            );

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                message: 'Task updated successfully',
                                task: serialized,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 5. complete_task - Toggle task completion
    tools.push({
        name: 'complete_task',
        description: 'Mark a task as completed or reopen it',
        inputSchema: {
            type: 'object',
            properties: {
                id: {
                    type: ['number', 'string'],
                    description: 'Task ID or UID',
                },
            },
            required: ['id'],
        },
        handler: async (params) => {
            const task = await findTaskByIdentifier(params.id, context.userId);

            if (!task) {
                throw new Error(`Task not found: ${params.id}`);
            }

            if (task.user_id !== context.userId) {
                throw new Error('Access denied');
            }

            // Toggle completion
            const newStatus = task.status === 2 ? 0 : 2; // 2 = completed, 0 = pending
            const updates = {
                status: newStatus,
                completed_at: newStatus === 2 ? new Date() : null,
            };

            await task.update(updates);

            const reloadedTask = await taskRepository.findByIdAndUser(
                task.id,
                context.userId,
                {
                    include: [
                        { model: Project, as: 'Project' },
                        { model: Tag, as: 'Tags' },
                    ],
                }
            );

            const serialized = await serializeTask(
                reloadedTask,
                context.user.timezone
            );

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                message:
                                    newStatus === 2
                                        ? 'Task completed'
                                        : 'Task reopened',
                                task: serialized,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 6. delete_task - Delete task
    tools.push({
        name: 'delete_task',
        description: 'Permanently delete a task',
        inputSchema: {
            type: 'object',
            properties: {
                id: {
                    type: ['number', 'string'],
                    description: 'Task ID or UID',
                },
            },
            required: ['id'],
        },
        handler: async (params) => {
            const task = await findTaskByIdentifier(params.id, context.userId);

            if (!task) {
                throw new Error(`Task not found: ${params.id}`);
            }

            if (task.user_id !== context.userId) {
                throw new Error('Access denied');
            }

            await task.destroy();

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                message: 'Task deleted successfully',
                                task_id: params.id,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 7. add_subtask - Add subtask to parent
    tools.push({
        name: 'add_subtask',
        description: 'Add a subtask to an existing task',
        inputSchema: {
            type: 'object',
            properties: {
                parent_id: {
                    type: ['number', 'string'],
                    description: 'Parent task ID or UID',
                },
                name: {
                    type: 'string',
                    description: 'Subtask name',
                },
                priority: {
                    type: 'string',
                    enum: ['low', 'medium', 'high'],
                },
                due_date: {
                    type: 'string',
                    description: 'Due date',
                },
            },
            required: ['parent_id', 'name'],
        },
        handler: async (params) => {
            const parentTask = await findTaskByIdentifier(
                params.parent_id,
                context.userId
            );

            if (!parentTask) {
                throw new Error(`Parent task not found: ${params.parent_id}`);
            }

            if (parentTask.user_id !== context.userId) {
                throw new Error('Access denied');
            }

            const priorityMap = { low: 0, medium: 1, high: 2 };

            const subtaskData = {
                user_id: context.userId,
                name: params.name,
                parent_task_id: parentTask.id,
                priority: params.priority ? priorityMap[params.priority] : 1,
                status: 0,
                due_date: params.due_date || null,
                project_id: parentTask.project_id, // Inherit parent's project
            };

            const subtask = await taskRepository.create(subtaskData);

            const reloadedSubtask = await taskRepository.findByIdAndUser(
                subtask.id,
                context.userId,
                {
                    include: [
                        { model: Project, as: 'Project' },
                        { model: Tag, as: 'Tags' },
                    ],
                }
            );

            const serialized = await serializeTask(
                reloadedSubtask,
                context.user.timezone
            );

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(
                            {
                                message: 'Subtask created successfully',
                                subtask: serialized,
                            },
                            null,
                            2
                        ),
                    },
                ],
            };
        },
    });

    // 8. get_task_metrics - Get task statistics
    tools.push({
        name: 'get_task_metrics',
        description: 'Get task statistics and productivity metrics',
        inputSchema: {
            type: 'object',
            properties: {},
        },
        handler: async (params) => {
            // Get counts by status
            const openCount = await taskRepository.count({
                user_id: context.userId,
                status: { [Op.in]: [0, 1] }, // pending or in_progress
            });

            const completedCount = await taskRepository.count({
                user_id: context.userId,
                status: 2, // completed
            });

            // Get overdue tasks
            const now = new Date();
            const overdueCount = await taskRepository.count({
                user_id: context.userId,
                status: { [Op.in]: [0, 1] },
                due_date: { [Op.lt]: now },
            });

            // Get in_progress tasks
            const inProgressCount = await taskRepository.count({
                user_id: context.userId,
                status: 1,
            });

            // Get today's completions
            const startOfDay = new Date();
            startOfDay.setHours(0, 0, 0, 0);
            const todayCompletions = await taskRepository.count({
                user_id: context.userId,
                status: 2,
                completed_at: { [Op.gte]: startOfDay },
            });

            // Get this week's completions
            const startOfWeek = new Date();
            startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay());
            startOfWeek.setHours(0, 0, 0, 0);
            const weekCompletions = await taskRepository.count({
                user_id: context.userId,
                status: 2,
                completed_at: { [Op.gte]: startOfWeek },
            });

            const metrics = {
                open_tasks: openCount,
                completed_tasks: completedCount,
                overdue_tasks: overdueCount,
                in_progress_tasks: inProgressCount,
                completed_today: todayCompletions,
                completed_this_week: weekCompletions,
            };

            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify(metrics, null, 2),
                    },
                ],
            };
        },
    });
}

module.exports = { registerTaskTools };
