"""从 Ollama 本地服务读取模型上下文长度（``/api/show``）。"""

from __future__ import annotations

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


def ollama_origin_from_openai_compat_base(base_url: str) -> str:
    """
    OpenAI 兼容基址如 ``http://host:11434/v1`` → ``http://host:11434``。
    已是裸 origin（无 /v1）则去掉尾部斜杠。
    """
    u = (base_url or "").strip().rstrip("/")
    if u.lower().endswith("/v1"):
        u = u[:-3]
    return u.rstrip("/") or "http://127.0.0.1:11434"


def fetch_ollama_context_window_tokens(*, base_url: str, model: str, timeout_sec: float = 15.0) -> int | None:
    """
    调 ``POST {origin}/api/show``，从返回 JSON 中解析 ``context_length`` / ``num_ctx`` / model_info 嵌套字段。
    失败返回 ``None``。
    """
    origin = ollama_origin_from_openai_compat_base(base_url)
    name = (model or "").strip()
    if not name:
        return None
    req = urllib.request.Request(
        f"{origin}/api/show",
        data=json.dumps({"name": name}).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout_sec) as resp:
            raw = resp.read().decode("utf-8", errors="replace")
    except (urllib.error.URLError, OSError, TimeoutError, ValueError):
        return None
    try:
        data: dict[str, Any] = json.loads(raw)
    except json.JSONDecodeError:
        return None
    for key in ("context_length", "num_ctx"):
        v = data.get(key)
        if v is not None:
            try:
                n = int(v)
                return n if n > 0 else None
            except (TypeError, ValueError):
                pass
    mi = data.get("model_info")
    if isinstance(mi, dict):
        for k, v in mi.items():
            if isinstance(k, str) and ("context" in k.lower() or "ctx" in k.lower()):
                try:
                    n = int(v)
                    if n > 0:
                        return n
                except (TypeError, ValueError):
                    pass
    # 部分版本嵌在 parameters 字符串
    par = data.get("parameters")
    if isinstance(par, str) and par.strip():
        m = re.search(r"(?:num[_-]?ctx|context[_-]?length)\s*[=:\s]+(\d+)", par, re.I)
        if m:
            try:
                n = int(m.group(1))
                return n if n > 0 else None
            except ValueError:
                pass
    return None
