"""
AI-LSC — Ollama tool schema registration.

Registers AI-LSC tool schemas with Ollama's native ``/api/tools``
endpoint so that models running through Ollama can use function calling
to control the AI-LSC stack.

Ollama tool-use flow
--------------------
1. Register tools via ``POST /api/tools``  (this module)
2. Include tool names in ``POST /api/chat``  request
3. Model returns ``tool_call`` objects in its response
4. Client executes the tool call and sends the result back
5. Model continues the conversation with tool results

Usage
-----
    registrar = OllamaToolRegistrar(ollama_port=11434)
    registrar.register_all(tool_schemas)
"""

from __future__ import annotations

import json
import urllib.error
import urllib.request
from typing import Any

from ai_lsc.utils.logging import get_logger

logger = get_logger(__name__)


class OllamaToolRegistrar:
    """Register and manage tool schemas with a running Ollama instance.

    Parameters
    ----------
    ollama_port :
        Port of the Ollama API server.
    timeout :
        HTTP request timeout in seconds.
    """

    def __init__(
        self,
        ollama_port: int = 11434,
        timeout: float = 10.0,
    ) -> None:
        self.base_url = f"http://127.0.0.1:{ollama_port}"
        self.timeout = timeout
        self._registered: set[str] = set()

    # ── Registration ──────────────────────────────────────────────────

    def register_all(
        self,
        schemas: list[dict[str, Any]],
    ) -> dict[str, bool]:
        """Register a list of tool schemas with Ollama.

        Returns a dict mapping tool name → success bool.
        """
        results: dict[str, bool] = {}
        for schema in schemas:
            func = schema.get("function", {})
            name = func.get("name", "unknown")
            try:
                self._register_single(schema)
                self._registered.add(name)
                results[name] = True
                logger.info("Registered tool: %s", name)
            except Exception as exc:
                results[name] = False
                logger.warning("Failed to register %s: %s", name, exc)
        return results

    def register_single(
        self,
        schema: dict[str, Any],
    ) -> bool:
        """Register a single tool schema. Returns True on success."""
        func = schema.get("function", {})
        name = func.get("name", "unknown")
        try:
            self._register_single(schema)
            self._registered.add(name)
            logger.info("Registered tool: %s", name)
            return True
        except Exception as exc:
            logger.warning("Failed to register %s: %s", name, exc)
            return False

    def _register_single(self, schema: dict[str, Any]) -> None:
        """POST a single tool schema to Ollama's /api/tools endpoint."""
        # Extract just the function definition for Ollama
        func_def = schema.get("function", {})
        payload = json.dumps({
            "name": func_def.get("name"),
            "description": func_def.get("description", ""),
            "parameters": func_def.get("parameters", {"type": "object", "properties": {}}),
        }).encode("utf-8")

        url = f"{self.base_url}/api/tools"
        req = urllib.request.Request(
            url,
            data=payload,
            headers={"Content-Type": "application/json"},
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=self.timeout) as resp:
            if resp.status != 200:
                raise RuntimeError(
                    f"Ollama returned status {resp.status}"
                )

    # ── Querying ───────────────────────────────────────────────────────

    def list_registered_tools(self) -> list[str]:
        """Return names of tools registered in this session."""
        return sorted(self._registered)

    def check_ollama_health(self) -> bool:
        """Check if Ollama is reachable. Returns True if healthy."""
        try:
            req = urllib.request.Request(self.base_url + "/")
            with urllib.request.urlopen(
                req, timeout=self.timeout
            ) as resp:
                return resp.status == 200
        except Exception:
            return False

    def list_ollama_models(self) -> list[dict[str, Any]]:
        """Query Ollama for available models via /api/tags."""
        try:
            req = urllib.request.Request(
                f"{self.base_url}/api/tags",
                headers={"Content-Type": "application/json"},
            )
            with urllib.request.urlopen(
                req, timeout=self.timeout
            ) as resp:
                data = json.loads(resp.read().decode("utf-8"))
                return data.get("models", [])
        except Exception as exc:
            logger.warning("Failed to list models: %s", exc)
            return []
