"""Model Context Protocol (MCP) server for `be` — Hungarian Legal AI.

Lets an MCP-aware host (Claude Desktop, Cursor, custom orchestrators) call
the deployed `be` API as if it were a local toolset. The server speaks
stdio MCP and uses the Python SDK to reach a live `be` deployment.

Install:
    pip install mcp httpx
    # Drop sdks/python/be_sdk.py next to this file, or pip install be-sdk
    # (this script assumes be_sdk is importable).

Claude Desktop config snippet (~/Library/Application Support/Claude/claude_desktop_config.json):

    {
      "mcpServers": {
        "jurisafe": {
          "command": "python",
          "args": ["/absolute/path/to/jurisafe_mcp_server.py"],
          "env": {
            "BE_BASE_URL": "https://be.example.com",
            "BE_API_KEY":  "be_apikey_..."
          }
        }
      }
    }

After restarting Claude Desktop, every chat gains these tools:
  - be_ask                  one-shot legal question, returns assistant text
  - be_find_statute         retrieve a specific § by short reference + locator
  - be_search_corpus        cross-resource search (conversations + documents)
  - be_list_presets         list practice-area presets (csaladjog, vallalkozoi, …)
  - be_generate_document    author a HU legal document (felszólítás, szerződés, …)
  - be_list_documents       list the caller's generated documents
  - be_get_document         TRANSMIT a document's content (md/html text, or
                            pdf/docx base64) to attach/insert anywhere
  - be_storage_mode         read/set storage mode (central | blockchain)
"""

from __future__ import annotations

import os
import sys
from typing import Any

try:
    from mcp.server.fastmcp import FastMCP
except ImportError:  # pragma: no cover
    sys.stderr.write(
        "jurisafe_mcp_server requires `mcp`. Install with: pip install mcp\n"
    )
    raise

# The SDK lives one directory up — make it importable when this file is run
# directly without packaging the SDK.
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(_HERE, "..", "sdks", "python"))

from be_sdk import BeClient, BeError  # noqa: E402


BASE_URL = os.environ.get("BE_BASE_URL", "http://127.0.0.1:8765")
API_KEY = os.environ.get("BE_API_KEY")
X402_TOKEN = os.environ.get("BE_X402_TOKEN")

mcp = FastMCP("jurisafe")
_client = BeClient(BASE_URL, api_key=API_KEY, x402_token=X402_TOKEN)


@mcp.tool()
def be_ask(question: str, preset: str | None = None) -> str:
    """Ask the `be` Hungarian legal AI a question and return the answer.

    Args:
        question: Hungarian-language legal question.
        preset:   Optional practice area — one of: csaladjog, vallalkozoi,
                  buntetojog, adojog, munkajog. Constrains retrieval to
                  the relevant body of law.

    Returns the assistant's grounded answer text (with inline § citations).
    """
    try:
        return _client.ask(question, preset=preset)
    except BeError as e:
        return f"Hiba: {e}"


@mcp.tool()
def be_find_statute(law: str, section: str) -> dict[str, Any]:
    """Fetch a precise statute text by short reference + § locator.

    Args:
        law:     Short reference, e.g. "Ptk.", "Btk.", "Mt.", "Kbt.", "GDPR".
        section: § locator, e.g. "6:8. §", "6:155. § (1)", "64. §".

    Returns ``{"text": str, "citation": {"short_ref", "locator", "url", "status"}}``.
    """
    try:
        return _client.statute(law=law, section=section)
    except BeError as e:
        return {"error": str(e)}


@mcp.tool()
def be_search_corpus(query: str, limit: int = 10) -> list[dict[str, Any]]:
    """Cross-resource search across the caller's conversations + documents.

    Useful when the caller wants the MCP host to recall prior client work
    by keyword. Requires a personal API key (the search is per-user).
    """
    try:
        return _client.search(query, limit=limit)
    except BeError as e:
        return [{"error": str(e)}]


@mcp.tool()
def be_list_presets() -> list[dict[str, Any]]:
    """List available practice-area presets the agent can pass to be_ask."""
    try:
        return _client.presets()
    except BeError as e:
        return [{"error": str(e)}]


@mcp.tool()
def be_generate_document(instructions: str, preset: str | None = None) -> dict[str, Any]:
    """Have `be` author a Hungarian legal document (felszólítás, szerződés,
    meghatalmazás, beadvány, kereset, nyilatkozat…) from natural-language
    instructions, then return the new document's record:
    ``{doc_id, title, doc_type, formats}``. Use be_get_document to fetch the
    actual content for transmission (e-mail, Word, Google Docs, DMS).
    """
    try:
        rec = _client.generate_document(instructions, preset=preset)
        return rec or {"error": "no document produced"}
    except BeError as e:
        return {"error": str(e)}


@mcp.tool()
def be_list_documents() -> list[dict[str, Any]]:
    """List the caller's generated documents (newest first). Requires a
    personal API key (documents are per-user)."""
    try:
        return _client.documents.list()
    except BeError as e:
        return [{"error": str(e)}]


@mcp.tool()
def be_get_document(doc_id: str, fmt: str = "md") -> dict[str, Any]:
    """TRANSMIT a generated document's content. `fmt`: md | html | pdf | docx.
    Text formats (md/html) are returned inline; binary (pdf/docx) is returned
    base64-encoded so an MCP host can save/attach it anywhere.
    """
    import base64

    try:
        data = _client.documents.download(doc_id, fmt)
        if fmt in ("md", "html", "txt"):
            return {"doc_id": doc_id, "format": fmt, "content": data.decode("utf-8", "replace")}
        return {"doc_id": doc_id, "format": fmt, "base64": base64.b64encode(data).decode()}
    except BeError as e:
        return {"error": str(e)}


@mcp.tool()
def be_storage_mode(mode: str | None = None) -> dict[str, Any]:
    """Read (no arg) or set the data-storage mode: 'central' or 'blockchain'
    (decentralized; only if the deployment enabled it)."""
    try:
        return _client.set_storage_mode(mode) if mode else _client.storage_mode()
    except BeError as e:
        return {"error": str(e)}


if __name__ == "__main__":
    mcp.run()
