from __future__ import annotations

from typing import Annotated

from mcp.server.fastmcp import FastMCP
from mcp.types import TextContent, ToolAnnotations
from pydantic import Field

from .. import routes
from ..client import ApiClient
from ..decorators import handle_api_errors
from .constants import DEFAULT_PAGE_SIZE, FEEDBACK_INSTRUCTION, SOURCE


def register(
    mcp: FastMCP,
    client: ApiClient,
    *,
    source_type: str,
    read_hint: ToolAnnotations,
    write_hint: ToolAnnotations,
    track,
) -> None:
    @mcp.tool(annotations=read_hint.model_copy(update={"title": "List Topics"}))
    @handle_api_errors
    @track
    async def list_topics(
        cursor: Annotated[
            str | None, Field(description="Pagination cursor from a previous call (omit for first page).", default=None)
        ] = None,
        limit: Annotated[int, Field(description="Max topics to return per page.", ge=1, le=100)] = DEFAULT_PAGE_SIZE,
        session_token: Annotated[
            str | None,
            Field(
                description="Session token from a previous call. Pass it back to continue the session.", default=None
            ),
        ] = None,
    ) -> list[TextContent]:
        """List all topics available to the current user.
        Call this to help the user identify which topic they want to work within.

        If has_more is true, call again with the returned cursor to get the next page.
        """
        params: dict = {"source": SOURCE, "limit": limit}
        if cursor:
            params["cursor"] = cursor
        if session_token:
            params["session_token"] = session_token
        data = await client.get(routes.topics(), params)
        topics = data.get("results", [])
        if not topics:
            return [TextContent(type="text", text="No topics found.")]

        results = []
        for t in topics:
            item_count = t.get("item_count", 0)
            desc = f"\n  Description: {t['description']}" if t.get("description") else ""
            results.append(f"**{t['name']}**{desc}\n- ID: {t['id']}\n- Knowledge Count: {item_count}")

        blocks = [TextContent(type="text", text="\n\n".join(results))]
        if data.get("has_more"):
            blocks.append(
                TextContent(
                    type="text",
                    text=f'Call again with cursor="{data["next_cursor"]}" to get the next page.',
                )
            )

        session_token = data.get("session_token")
        if session_token:
            blocks.append(TextContent(type="text", text=f"Session: {session_token}"))

        if data.get("feedback_enabled"):
            blocks.append(TextContent(type="text", text=FEEDBACK_INSTRUCTION))

        return blocks

    @mcp.tool(annotations=write_hint.model_copy(update={"title": "Create Topic"}))
    @handle_api_errors
    @track
    async def create_topic(
        name: Annotated[str, Field(description="Name of the topic.")],
        description: Annotated[str, Field(description="Optional description of the topic.", default="")] = "",
    ) -> list[TextContent]:
        """Create a new topic to organize knowledge.

        Only call this when the user explicitly asks to create a topic.
        Do not create topics automatically or preemptively.
        """
        data = await client.post(routes.topics(), {"name": name, "description": description})
        desc = data.get("description") or "(none)"
        return [
            TextContent(
                type="text",
                text=f"Topic created:\n- **{data['name']}**\n- ID: {data['id']}\n- Description: {desc}",
            )
        ]

    @mcp.prompt(
        name="topic_knowledge",
        title="Get Topic Knowledge",
        description="Pull knowledge from an Obris topic into the conversation",
    )
    async def topic_knowledge_prompt(
        topic_name: Annotated[str, Field(description="Name of the topic to pull knowledge from")],
    ) -> str:
        return f"Using my Obris knowledge, pull in my {topic_name} topic and use it as context for this conversation."
