"""Built-in web tools backed by Jina Reader/Search."""

from __future__ import annotations

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

from memnixa.tools.base import Tool, paginate_text


class ReadUrlTool(Tool):
    """Read webpage contents through Jina Reader."""

    name = "read_url"
    description = (
        "Read webpage content through Jina Reader with paginated text output. "
        "This tool works without a Jina key, but adding 'jina_api_key' in config.json "
        "or setting JINA_API_KEY is recommended for reliable access."
    )
    parameters = {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "url": {
                "type": "string",
                "description": "HTTP or HTTPS URL to fetch.",
                "minLength": 1,
            },
            "page": {
                "type": "integer",
                "description": "1-based result page.",
                "minimum": 1,
            },
            "page_size": {
                "type": "integer",
                "description": "Number of characters per page.",
                "minimum": 256,
                "maximum": 12000,
            },
        },
        "required": ["url"],
    }

    def __init__(self, *, api_key: str = "", timeout: int = 120):
        self.api_key = api_key.strip()
        self.timeout = timeout

    def execute(self, arguments: dict[str, Any]):
        target_url = _normalize_url(str(arguments["url"]))
        endpoint = (
            "https://r.jina.ai/"
            + urllib.parse.quote(target_url, safe=":/?&=#%+-_.~")
        )
        response = _request_jina_text(
            endpoint=endpoint,
            api_key=self.api_key,
            timeout=self.timeout,
        )
        if not response["ok"]:
            return self.failure(
                response["error"]["code"],
                response["error"]["message"],
                data=response.get("data"),
                meta=response.get("meta"),
            )

        try:
            content, pagination = paginate_text(
                str(response["text"]),
                page=int(arguments.get("page") or 1),
                page_size=int(arguments.get("page_size") or 4000),
            )
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))

        return self.success(
            data={
                "url": target_url,
                "content": content,
            },
            meta={
                "provider": "jina",
                "mode": "reader",
                "pagination": pagination,
                **response["meta"],
            },
        )


class SearchWebTool(Tool):
    """Search the web through Jina Search."""

    name = "search_web"
    description = (
        "Search the web through Jina Search with paginated text output. "
        "Requires 'jina_api_key' in config.json or the JINA_API_KEY environment variable. "
        "If the key is missing, stop and ask the user to update the config."
    )
    parameters = {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "query": {
                "type": "string",
                "description": "Search query.",
                "minLength": 1,
            },
            "page": {
                "type": "integer",
                "description": "1-based result page.",
                "minimum": 1,
            },
            "page_size": {
                "type": "integer",
                "description": "Number of characters per page.",
                "minimum": 256,
                "maximum": 12000,
            },
        },
        "required": ["query"],
    }

    def __init__(self, *, api_key: str = "", timeout: int = 120):
        self.api_key = api_key.strip()
        self.timeout = timeout

    def execute(self, arguments: dict[str, Any]):
        if not self.api_key:
            return self.failure(
                "config_required",
                (
                    "Jina search is not configured. Ask the user to set "
                    "'jina_api_key' in config.json or export JINA_API_KEY "
                    "before using search_web."
                ),
                meta={
                    "config_path": "config.json",
                    "config_field": "jina_api_key",
                    "env_var": "JINA_API_KEY",
                },
            )
        query = str(arguments["query"]).strip()
        endpoint = "https://s.jina.ai/" + urllib.parse.quote(query, safe="")
        response = _request_jina_text(
            endpoint=endpoint,
            api_key=self.api_key,
            timeout=self.timeout,
        )
        if not response["ok"]:
            return self.failure(
                response["error"]["code"],
                response["error"]["message"],
                data=response.get("data"),
                meta=response.get("meta"),
            )

        try:
            content, pagination = paginate_text(
                str(response["text"]),
                page=int(arguments.get("page") or 1),
                page_size=int(arguments.get("page_size") or 4000),
            )
        except ValueError as exc:
            return self.failure("page_out_of_range", str(exc))

        return self.success(
            data={
                "query": query,
                "content": content,
            },
            meta={
                "provider": "jina",
                "mode": "search",
                "pagination": pagination,
                **response["meta"],
            },
        )


def _normalize_url(raw_url: str) -> str:
    candidate = raw_url.strip()
    if "://" not in candidate:
        candidate = "https://" + candidate
    parsed = urllib.parse.urlparse(candidate)
    if parsed.scheme not in {"http", "https"} or not parsed.netloc:
        raise ValueError("url must be a valid http or https URL")
    return urllib.parse.urlunparse(parsed)


def _request_jina_text(
    *,
    endpoint: str,
    api_key: str,
    timeout: int,
) -> dict[str, Any]:
    headers = {
        "Accept": "text/plain; charset=utf-8",
        "User-Agent": "Memnixa/0.1.0",
    }
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"
    request = urllib.request.Request(endpoint, headers=headers, method="GET")
    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            return {
                "ok": True,
                "text": response.read().decode("utf-8", errors="replace"),
                "meta": {
                    "endpoint": endpoint,
                    "status_code": int(getattr(response, "status", 200)),
                    "content_type": str(response.headers.get("Content-Type") or ""),
                    "final_url": response.geturl(),
                },
            }
    except urllib.error.HTTPError as exc:
        body = exc.read().decode("utf-8", errors="replace")
        return {
            "ok": False,
            "error": {
                "code": "http_error",
                "message": f"Jina request failed with HTTP {exc.code}",
            },
            "data": {
                "body": body[:4000],
            },
            "meta": {
                "endpoint": endpoint,
                "status_code": int(exc.code),
            },
        }
    except urllib.error.URLError as exc:
        return {
            "ok": False,
            "error": {
                "code": "network_error",
                "message": f"Network error: {exc.reason}",
            },
            "meta": {
                "endpoint": endpoint,
            },
        }
