"""MCP tools for retrieving externalized tool results."""

from typing import Annotated, Any

from arcade_tdk import ToolContext, tool

from cadecoder.core.logging import log
from cadecoder.execution.tool_result_store import (
    RetrieveMode,
    ToolResultStore,
    get_content_lines,
    navigate_json,
    search_content,
    summarize_content,
)


def _get_store() -> ToolResultStore:
    """Get or create the shared ToolResultStore instance."""
    return ToolResultStore()


@tool(
    name="RetrieveToolResult",
    desc=(
        "Retrieve an externalized tool result using different strategies. "
        "Modes: 'full' returns raw content with pagination (default); "
        "'search' finds lines matching a regex/substring query with surrounding context; "
        "'summarize' returns a structural overview without loading full content; "
        "'lines' returns a specific line range; "
        "'json' navigates JSON content by path and depth for progressive exploration; "
        "'list' browses available stored results with metadata. "
        "Prefer 'json' (depth=0 or 1), 'summarize', or 'search' first to avoid "
        "loading large results into context."
    ),
)
def retrieve_tool_result_tool(
    context: ToolContext,
    record_id: Annotated[
        str,
        "The record ID from the [EXTERNALIZED_RESULT] reference. "
        "Required for all modes except 'list'.",
    ] = "",
    name: Annotated[
        str,
        "Name of a pinned context snippet (shorthand for looking up UserContext by name).",
    ] = "",
    mode: Annotated[
        RetrieveMode,
        "Retrieval strategy: 'full' (raw, paginated), 'search' (regex/substring match), "
        "'summarize' (structural overview), 'lines' (specific line range), "
        "'json' (navigate JSON by path/depth), 'list' (browse available results).",
    ] = RetrieveMode.FULL,
    # -- full mode params --
    max_chars: Annotated[
        int,
        "Max characters to return for 'full' mode. Defaults to 30000.",
    ] = 30_000,
    offset: Annotated[
        int,
        "Character offset for 'full' mode pagination. Defaults to 0.",
    ] = 0,
    # -- search mode params --
    query: Annotated[
        str,
        "Regex or substring to search for (required for 'search' mode).",
    ] = "",
    context_lines: Annotated[
        int,
        "Lines of surrounding context to include around each match (for 'search' mode). Defaults to 2.",
    ] = 2,
    # -- lines mode params --
    start_line: Annotated[
        int,
        "First line to return, 1-indexed (for 'lines' mode). Defaults to 1.",
    ] = 1,
    end_line: Annotated[
        int,
        "Last line to return, 1-indexed inclusive (for 'lines' mode). Defaults to 50.",
    ] = 50,
    # -- json mode params --
    json_path: Annotated[
        str,
        "Dot-bracket path to navigate JSON (for 'json' mode). "
        "Examples: '' (root), 'emails', 'emails[0]', 'emails[0].subject'.",
    ] = "",
    depth: Annotated[
        int,
        "Depth of JSON to render (for 'json' mode). "
        "0=type/size only, 1=one level, 2=two levels. Omit for full depth.",
    ] = -1,
    # -- list mode params --
    thread_id: Annotated[
        str,
        "Filter by thread ID (for 'list' mode).",
    ] = "",
    tool_name: Annotated[
        str,
        "Filter by tool name, e.g. 'Google_ReadEmail' (for 'list' mode).",
    ] = "",
    limit: Annotated[
        int,
        "Maximum number of results to return (for 'list' mode). Defaults to 20.",
    ] = 20,
) -> Annotated[dict[str, Any], "Tool result content based on retrieval mode."]:
    """Retrieve externalized tool result content using the selected strategy."""
    store = _get_store()

    # -- list mode: doesn't require record_id --
    if mode == RetrieveMode.LIST:
        records = store.list_records(
            thread_id=thread_id or None, tool_name=tool_name or None, limit=limit
        )
        items = [
            {
                "record_id": r.record_id,
                "tool_name": r.tool_name,
                "name": r.name,
                "summary": r.summary,
                "content_chars": r.content_chars,
                "content_token_estimate": r.content_token_estimate,
                "status": r.status,
                "timestamp": r.timestamp,
                "thread_id": r.thread_id,
            }
            for r in records
        ]
        return {
            "mode": "list",
            "results": items,
            "total": len(items),
            "message": (
                f"{len(items)} tool results found."
                if items
                else "No tool results found matching the criteria."
            ),
        }

    # -- name-based lookup for pinned context --
    if name and not record_id:
        named_record = store.get_user_context_by_name(thread_id, name)
        if named_record:
            record_id = named_record.record_id
        else:
            return {"error": f"No pinned context named '{name}' found."}

    # -- all other modes require record_id --
    if not record_id:
        return {
            "error": "Parameter 'record_id' is required for this mode.",
            "hint": "Use mode='list' to browse available records.",
        }

    record = store.retrieve(record_id)
    if record is None:
        log.warning(f"Tool result not found: {record_id}")
        return {
            "error": f"Record {record_id} not found.",
            "hint": "Use mode='list' to see available records.",
        }

    base: dict[str, Any] = {
        "record_id": record.record_id,
        "tool_name": record.tool_name,
        "status": record.status,
        "total_chars": len(record.content),
    }

    if mode == RetrieveMode.FULL:
        content = record.content
        total_chars = len(content)
        if offset > 0:
            content = content[offset:]
        truncated = len(content) > max_chars
        if truncated:
            content = content[:max_chars]

        result: dict[str, Any] = {
            **base,
            "mode": "full",
            "content": content,
            "summary": record.summary,
            "tool_call_id": record.tool_call_id,
            "offset": offset,
            "returned_chars": len(content),
        }
        if truncated:
            next_offset = offset + max_chars
            result["truncated"] = True
            result["next_offset"] = next_offset
            result["remaining_chars"] = total_chars - next_offset
            result["hint"] = (
                f"Content truncated. Use offset={next_offset} to read the next chunk, "
                "or try mode='search', mode='json', or mode='summarize' for targeted retrieval."
            )
        return result

    elif mode == RetrieveMode.SEARCH:
        if not query:
            return {**base, "error": "Parameter 'query' is required for mode='search'."}
        return {
            **base,
            "mode": "search",
            "query": query,
            **search_content(record.content, query, context_lines=context_lines),
        }

    elif mode == RetrieveMode.SUMMARIZE:
        return {
            **base,
            "mode": "summarize",
            **summarize_content(record.content, record.tool_name, record.status),
        }

    elif mode == RetrieveMode.LINES:
        return {
            **base,
            "mode": "lines",
            **get_content_lines(record.content, start_line, end_line),
        }

    elif mode == RetrieveMode.JSON:
        return {
            **base,
            "mode": "json",
            **navigate_json(record.content, json_path, depth if depth >= 0 else None, max_chars),
        }

    else:
        return {
            **base,
            "error": f"Unknown mode '{mode}'. Use: {', '.join(m.value for m in RetrieveMode)}.",
        }
