"""MCP tool registrations for tasks."""

from mcp.server.fastmcp import Context


def register_tools(mcp, api_fn):
    @mcp.tool()
    async def create_task(
        project_id: str,
        title: str,
        description: str = "",
        priority: str = "medium",
        status: str = "todo",
        commit_base: str = "",
        commit_head: str = "",
        branch: str = "",
        worktree_path: str = "",
        pr_url: str = "",
        feature_id: int | None = None,
        depends_on: list[int] | None = None,
        ctx: Context = None,
    ) -> dict | str:
        """Create a new task within a project.

        The project must already exist. If it does not, call create_project first
        to register it, then retry create_task.

        Args:
            project_id: The project this task belongs to (org/repo format, e.g. 'pyrabbit/peon-mcp').
            title: Short summary of the task.
            description: Detailed description of the work to be done.
            priority: One of 'low', 'medium', 'high', or 'critical'.
            status: One of 'grooming', 'todo', 'in_progress', 'done', or 'cancelled'.
            commit_base: Git commit SHA when work began (captured at in_progress).
            commit_head: Git commit SHA after work completed (captured at done).
            branch: Git branch name for this task's work.
            worktree_path: Path to the git worktree for this task.
            pr_url: URL of the pull request created for this task.
            feature_id: ID of the feature this task belongs to (optional).
            depends_on: List of task IDs this task depends on (optional).
        """
        return await api_fn(ctx).create_task(
            project_id, title, description, priority, status,
            commit_base, commit_head, branch, worktree_path, pr_url, feature_id,
            depends_on,
        )

    @mcp.tool()
    async def list_tasks(
        project_id: str,
        priority: str | None = None,
        status: str | None = None,
        feature_id: int | None = None,
        sort: str | None = None,
        ctx: Context = None,
    ) -> list[dict]:
        """List tasks for a project, optionally filtered by priority and/or status.

        Args:
            project_id: The project to list tasks for (org/repo format, e.g. 'pyrabbit/peon-mcp').
            priority: Filter by priority ('low', 'medium', 'high', 'critical'). Omit to show all.
            status: Filter by status ('grooming', 'todo', 'in_progress', 'done', 'cancelled'). Omit to show all.
            feature_id: Filter by feature ID. Omit to show all.
            sort: Sort by 'priority' (default), 'status', 'created', 'updated', 'started', or 'completed'.
        """
        return await api_fn(ctx).list_tasks(project_id, priority, status, feature_id, sort)

    @mcp.tool()
    async def get_task(task_id: int, ctx: Context = None) -> dict | str:
        """Get a single task by its ID.

        Args:
            task_id: The numeric ID of the task.
        """
        return await api_fn(ctx).get_task(task_id)

    @mcp.tool()
    async def next_task(project_id: str = "", commit_base: str = "", feature_id: int | None = None, host: str = "", ctx: Context = None) -> dict | str:
        """Pick up the next task to work on for a project.

        Returns the highest-priority task with status 'todo' (critical > high >
        medium > low, oldest first within the same priority) and automatically
        marks it as 'in_progress'.

        Uses optimistic concurrency control to prevent race conditions when multiple
        agents call next_task() concurrently. If another agent claims the task between
        our SELECT and UPDATE, we retry with the next available task.

        Args:
            project_id: The project to pick the next task from (org/repo format, e.g. 'pyrabbit/peon-mcp'). If empty, searches all projects.
            commit_base: Git commit SHA at the time work begins (from git rev-parse HEAD).
            feature_id: Filter to tasks within a specific feature (optional).
            host: Hostname of the caller (e.g. pod name). Used to track which worker claimed the task.
        """
        return await api_fn(ctx).next_task(project_id, commit_base, feature_id, host)

    @mcp.tool()
    async def update_task(
        task_id: int,
        title: str | None = None,
        description: str | None = None,
        priority: str | None = None,
        status: str | None = None,
        commit_base: str | None = None,
        commit_head: str | None = None,
        branch: str | None = None,
        worktree_path: str | None = None,
        pr_url: str | None = None,
        feature_id: int | None = None,
        lines_added: int | None = None,
        lines_deleted: int | None = None,
        tokens_used: int | None = None,
        ctx: Context = None,
    ) -> dict | str:
        """Update fields on an existing task.

        Dependency validation: transitioning status to 'in_progress' is rejected
        with a 409 error if any dependency task is not yet 'done' or 'cancelled'.

        Args:
            task_id: The numeric ID of the task to update.
            title: New title (optional).
            description: New description (optional).
            priority: New priority — 'low', 'medium', 'high', or 'critical' (optional).
            status: New status — 'grooming', 'todo', 'in_progress', 'done', or 'cancelled' (optional).
            commit_base: Git commit SHA when work began (optional).
            commit_head: Git commit SHA after work completed (optional).
            branch: Git branch name for this task's work (optional).
            worktree_path: Path to the git worktree for this task (optional).
            pr_url: URL of the pull request created for this task (optional).
            feature_id: ID of the feature this task belongs to (optional).
            lines_added: Number of lines added (REQUIRED when status='done').
            lines_deleted: Number of lines deleted (REQUIRED when status='done').
            tokens_used: Number of tokens used (REQUIRED when status='done').
        """
        return await api_fn(ctx).update_task(
            task_id, title, description, priority, status,
            commit_base, commit_head, branch, worktree_path, pr_url,
            feature_id, lines_added, lines_deleted, tokens_used,
        )

    @mcp.tool()
    async def update_task_progress(
        task_id: int,
        progress: float,
        ctx: Context = None,
    ) -> dict | str:
        """Update the progress of a task.

        **CRITICAL**: Call this tool FREQUENTLY throughout your work, not just at major milestones.
        Stakeholders monitor task progress in real-time. Aim to call this at least 3-4 times per
        task, ideally after every significant action (reading files, writing code, running tests, etc.).

        Progress is represented as a decimal value from 0.0 (not started) to 1.0 (complete).
        Progress can only increase, never decrease.

        Args:
            task_id: The numeric ID of the task to update.
            progress: Progress value between 0.0 and 1.0 (must be >= current progress).
        """
        return await api_fn(ctx).update_task_progress(task_id, progress)
