"""Issue-side handlers: create_issue, update_issue_toc, move_project_item,
close_issue_with_comment."""
from __future__ import annotations

from mcp.types import TextContent

from ...context import ServerContext
from ...models import CreateIssueResult, OperationError
from ...utils import check_overwrite_size
# Late binding — see helpers.py docstring.
from active_claude_github_mcp import server as _s
from ..helpers import TYPE_LABELS, err, fetch_project_toc_body, ok


async def create_issue_tool(
    ctx: ServerContext,
    title: str,
    body: str,
    labels: list[str],
    discussion_origin_id: str,
    owner: str,
    repo: str,
) -> list[TextContent]:
    seen: set[str] = set()
    type_labels: set[str] = set()
    for name in labels:
        if not isinstance(name, str) or not name.strip():
            raise ValueError(
                f"Each label must be a non-empty string, got: {name!r}"
            )
        if name in seen:
            raise ValueError(f"Duplicate label: {name!r}")
        seen.add(name)
        if name in TYPE_LABELS:
            type_labels.add(name)
    if len(type_labels) != 1:
        raise ValueError(
            "Exactly one type label is required from "
            f"{sorted(TYPE_LABELS)}. Got: {sorted(type_labels) or '(none)'}"
        )

    repo_id = _s.get_repo_node_id(ctx.github_token, owner, repo)
    label_ids = [
        _s.get_label_id(ctx.github_token, owner, repo, name) for name in labels
    ]

    issue = _s.create_issue(ctx.github_token, repo_id, title, body, label_ids)
    project_item_id = _s.add_item_to_project(
        ctx.github_token, ctx.config.project_board.id, issue["id"]
    )
    ctx.activity.issues_created += 1

    return ok(
        CreateIssueResult(
            issue_id=issue["id"],
            issue_number=issue["number"],
            issue_url=issue["url"],
            project_item_id=project_item_id,
            project_toc_body=fetch_project_toc_body(
                ctx.github_token, ctx.config.project_discussion_id
            ),
        ).model_dump()
    )


async def update_issue_toc(
    ctx: ServerContext,
    issue_id: str,
    new_body: str,
    force: bool,
) -> list[TextContent]:
    current_body = _s.get_issue_body(ctx.github_token, issue_id)
    check_overwrite_size(current_body, new_body, force)
    _s.update_issue_body(ctx.github_token, issue_id, new_body)
    return ok("Issue opening post updated.")


async def move_project_item(
    ctx: ServerContext,
    column_name: str,
    issue_id: str,
) -> list[TextContent]:
    board = ctx.config.project_board
    if board.status_field_id and board.status_options:
        status_field_id = board.status_field_id
        options = board.status_options
    else:
        field_info = _s.get_project_status_field(ctx.github_token, board.id)
        status_field_id = field_info["field_id"]
        options = field_info["options"]
    option_id = options.get(column_name)
    if not option_id:
        return err(
            OperationError(
                success=False,
                error=f"Column '{column_name}' not found on board.",
                buffered=False,
                buffer_file=None,
                retry_tool=None,
                retry_args=None,
            )
        )
    project_item_id = _s.get_project_item_id(
        ctx.github_token, issue_id, board.id
    )
    _s.move_project_item(
        ctx.github_token, board.id, project_item_id, status_field_id, option_id
    )
    return ok(f"Moved to {column_name}.")


async def close_issue_with_comment(
    ctx: ServerContext,
    issue_id: str,
    comment: str,
    state_reason: str,
) -> list[TextContent]:
    if not comment.strip():
        raise ValueError("comment must not be empty.")
    # Post the comment first so it appears above the close event
    # on the Issue timeline (#59).
    _s.add_issue_comment(ctx.github_token, issue_id, comment)
    closed = _s.close_issue(
        ctx.github_token, issue_id, state_reason=state_reason
    )
    return ok(
        {
            "issue_url": closed["url"],
            "closed_at": closed["closed_at"],
        }
    )
