"""MCP server exposing pygittools task boards to AI clients."""

from __future__ import annotations

import json
import os

from mcp.server import MCPServer
from pygittools.tasks import Task, _parse_dt, create_task
from pygittools.tasks_query import (
    BoardColumnView,
    BoardView,
    RepoLocation,
    TaskView,
    board_ref,
    discover_repo_path,
    get_board,
    get_board_tasks_grouped,
    get_task_view,
    list_boards,
    list_tasks,
    open_repository,
    resolve_repo_location,
)

from pygittools_mcp.exceptions import (
    BoardNotFoundError,
    InvalidTaskDueDateError,
    InvalidTaskPriorityError,
    InvalidTaskStatusError,
    TaskNotFoundError,
)
from pygittools_mcp.models import CreateTaskToolResult

mcp = MCPServer(
    "pygittools-tasks",
    instructions=(
        "Read task boards stored as Git annotated tags. "
        "Boards live under refs/tags/boards/, tasks under refs/tags/tasks/, "
        "and comments under refs/tags/comments/. "
        "Set PYGITTOOLS_REPO to a repository path, or PYGITWEB_PROJECTROOT plus a project name."
    ),
)


def _repo_for_tool(project: str | None = None) -> RepoLocation:
    return resolve_repo_location(project=project)


@mcp.tool(title="List boards")
def list_boards_tool(project: str | None = None) -> list[BoardView]:
    """List all task boards in the configured repository."""
    location = _repo_for_tool(project)
    repo = open_repository(location)
    return list_boards(repo)


@mcp.tool(title="List tasks")
def list_tasks_tool(
    board: str = "Tasks",
    project: str | None = None,
    include_comments: bool = True,
) -> list[TaskView]:
    """List tasks on a board, optionally including comment bodies."""
    location = _repo_for_tool(project)
    repo = open_repository(location)
    try:
        return list_tasks(repo, board, include_comments=include_comments)
    except KeyError as exc:
        raise BoardNotFoundError(board) from exc


@mcp.tool(title="Get task")
def get_task_tool(task_ref: str, project: str | None = None) -> TaskView:
    """Get one task by ref slug (task_123) or full ref (refs/tags/tasks/task_123)."""
    location = _repo_for_tool(project)
    repo = open_repository(location)
    try:
        return get_task_view(repo, task_ref, include_comments=True)
    except KeyError as exc:
        raise TaskNotFoundError(task_ref) from exc


@mcp.tool(title="Create task")
def create_task_tool(
    title: str,
    description: str,
    board: str = "Tasks",
    status: str = "TODO",
    priority: str = "LOW",
    assignee: str = "",
    due_date: str | None = None,
    tags: str | None = None,
    points: int | None = None,
    project: str | None = None,
) -> CreateTaskToolResult:
    """Create a new task on a board."""
    location = _repo_for_tool(project)
    repo = open_repository(location)
    try:
        b = get_board(repo, board_ref(board))
        if b is None:
            raise BoardNotFoundError(board)
    except KeyError as e:
        raise BoardNotFoundError(board) from e

    try:
        s = Task.Status(status)
    except ValueError as e:
        raise InvalidTaskStatusError(status) from e

    try:
        p = Task.Priority(priority)
    except ValueError as e:
        raise InvalidTaskPriorityError(priority) from e

    try:
        d = _parse_dt(due_date)
    except ValueError as e:
        raise InvalidTaskDueDateError(due_date or "") from e

    try:
        result = create_task(
            repo=repo,
            board=b,
            title=title,
            description=description,
            status=s,
            priority=p,
            assignee=assignee,
            due_date=d,
            tags=tags or "",
            points=points,
        )
        return {"task_id": result["id"], "ref": result["ref"], "oid": str(result["oid"])}
    except Exception:
        raise


@mcp.tool(title="Board grouped by status")
def board_by_status_tool(
    board: str = "Tasks",
    project: str | None = None,
    include_comments: bool = True,
) -> list[BoardColumnView]:
    """Return board tasks grouped into status columns (TODO, IN_PROGRESS, etc.)."""
    location = _repo_for_tool(project)
    repo = open_repository(location)
    try:
        return get_board_tasks_grouped(repo, board, include_comments=include_comments)
    except KeyError as exc:
        raise ValueError(str(exc)) from exc


@mcp.resource("board://{board_name}")
def board_resource(board_name: str) -> str:
    """JSON snapshot of a board grouped by status."""
    location = resolve_repo_location()
    repo = open_repository(location)
    columns = get_board_tasks_grouped(repo, board_name, include_comments=True)
    return json.dumps(columns, indent=2)


@mcp.resource("task://{task_ref}")
def task_resource(task_ref: str) -> str:
    """JSON snapshot of a single task with comments."""
    location = resolve_repo_location()
    repo = open_repository(location)
    task = get_task_view(repo, task_ref, include_comments=True)
    return json.dumps(task, indent=2)


def main() -> None:
    repo_env = os.environ.get("PYGITTOOLS_REPO", "").strip()
    if not repo_env:
        try:
            discovered = discover_repo_path()
        except FileNotFoundError:
            discovered = None
        if discovered is not None:
            os.environ["PYGITTOOLS_REPO"] = str(discovered)
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()