"""Device-tool schemas — the tools the brain CALLS but the PHONE EXECUTES.

These are exposed to the LLM exactly like the server-side tools in ``tools.py``,
but they don't run in the gateway: when the brain calls one, the gateway resolves
any saved state it needs (a place for ``navigate``, a contact number for
``call_contact``), emits a WS ``action`` frame to the connected phone, and waits
for the matching ``action_result`` (see ``main.Session`` — the bridge — and
APP_PLAN.md §3b for the wire protocol). The result string is fed back into the
brain's tool loop.

This module holds ONLY the schemas + the name set; the executor/bridge lives on
``main.Session`` because it needs the live WebSocket and the phone store. Keeping
the schemas here lets ``main`` build the brain's toolset as
``tools.TOOL_SPECS + device_tools.DEVICE_TOOL_SPECS`` without a circular import.

The ``action`` name each tool maps to on the wire (what the phone switches on):
    navigate       -> "navigate"      call_contact   -> "call"
    play_music     -> "play_music"    take_screenshot -> "take_screenshot"
    open_camera    -> "open_camera"   open_app       -> "open_app"
    open_url       -> "open_url"      set_timer      -> "set_timer"
    get_location   -> "get_location"
"""

from __future__ import annotations


def _fn(name: str, description: str, properties: dict,
        required: list[str] | None = None) -> dict:
    return {
        "type": "function",
        "function": {
            "name": name,
            "description": description,
            "parameters": {
                "type": "object",
                "properties": properties,
                "required": required or [],
            },
        },
    }


DEVICE_TOOL_SPECS: list[dict] = [
    _fn("navigate",
        "Start turn-by-turn navigation on Ahmed's phone. Give a saved place "
        "label (I'll resolve the address) or a raw destination. Use for 'take me "
        "to…', 'navigate to the office'.",
        {"destination": {"type": "string",
                         "description": "A saved place label, an address, or a "
                                        "place name."}},
        ["destination"]),
    _fn("play_music",
        "Play music on Ahmed's phone. Use for 'play…', 'put on some…'.",
        {"query": {"type": "string",
                   "description": "Song / artist / playlist / mood to play."}},
        ["query"]),
    _fn("call_contact",
        "Place a phone call to a SAVED contact by name (I resolve the number "
        "privately — you never see or say it). Use for 'call my father', 'ring "
        "Sara'. If no number is saved, say so and offer to save one.",
        {"name": {"type": "string", "description": "The saved contact's name."}},
        ["name"]),
    _fn("take_screenshot",
        "Capture a screenshot on Ahmed's phone. Use for 'take a screenshot', "
        "'grab this screen'.",
        {}),
    _fn("open_camera",
        "Open the camera on Ahmed's phone. Use for 'open the camera', 'take a "
        "selfie', 'record a video'.",
        {"mode": {"type": "string", "enum": ["photo", "video", "selfie"],
                  "description": "Camera mode (default photo)."}},
        []),
    _fn("open_app",
        "Open an app on Ahmed's phone. Use for 'open WhatsApp', 'launch "
        "Spotify'.",
        {"target": {"type": "string",
                    "description": "App name or package to open."}},
        ["target"]),
    _fn("open_url",
        "Open a web link on Ahmed's phone. Use for 'open…', 'pull up the "
        "website'.",
        {"url": {"type": "string", "description": "The URL to open."}},
        ["url"]),
    _fn("set_timer",
        "Set a countdown timer on Ahmed's phone. Resolve durations yourself "
        "('five minutes' → 300 seconds).",
        {"seconds": {"type": "integer",
                     "description": "Duration in seconds."},
         "label": {"type": "string",
                   "description": "Optional label, e.g. 'pasta'."}},
        ["seconds"]),
    _fn("get_location",
        "Get Ahmed's current location from his phone. Use when you need where he "
        "is right now.",
        {}),
]

DEVICE_TOOL_NAMES: frozenset[str] = frozenset(
    spec["function"]["name"] for spec in DEVICE_TOOL_SPECS)

# Tool name -> the wire ``action`` verb the phone switches on. Where the tool
# name and wire verb differ it is because the gateway does resolution first
# (call_contact resolves a number, then dials via the "call" action).
TOOL_TO_ACTION: dict[str, str] = {
    "navigate": "navigate",
    "play_music": "play_music",
    "call_contact": "call",
    "take_screenshot": "take_screenshot",
    "open_camera": "open_camera",
    "open_app": "open_app",
    "open_url": "open_url",
    "set_timer": "set_timer",
    "get_location": "get_location",
}
