"""用户自定义 OpenAI 兼容 LLM 厂商 — providers.local 持久化。"""

from __future__ import annotations

import re
from typing import Any

from niannian.core.config import _load_yaml, resolve_providers_config_path
from niannian.llm.providers.registry import is_storage_provider

_PROVIDER_ID_RE = re.compile(r"^[a-z][a-z0-9_-]{1,31}$")

# 内置 catalog id，不可作为用户新建 custom id
_BUILTIN_LLM_IDS = frozenset(
    {
        "siliconflow",
        "openai_compat",
        "deepseek",
        "custom",
        "zhipu",
        "volcengine",
        "dashscope",
        "minimax",
        "baichuan",
        "moonshot",
        "qianfan",
        "spark",
        "anthropic",
    }
)


class CustomProviderError(Exception):
    pass


def load_providers_doc() -> dict[str, Any]:
    path = resolve_providers_config_path(for_write=True)
    if not path.is_file():
        return {}
    raw = _load_yaml(path)
    return raw if isinstance(raw, dict) else {}


def is_custom_provider_entry(entry: Any) -> bool:
    return isinstance(entry, dict) and bool(entry.get("custom_provider"))


def validate_custom_provider_id(provider_id: str) -> str:
    pid = (provider_id or "").strip().lower()
    if not _PROVIDER_ID_RE.match(pid):
        raise CustomProviderError(
            "provider_id 须为小写字母开头，仅含 a-z、0-9、_、-，长度 2–32"
        )
    if pid in _BUILTIN_LLM_IDS or is_storage_provider(pid):
        raise CustomProviderError(f"provider_id 不可用: {pid}")
    return pid


def custom_catalog_entry(provider_id: str, entry: dict[str, Any]) -> dict[str, Any]:
    return {
        "id": provider_id,
        "label": str(entry.get("label") or provider_id),
        "base_url": str(entry.get("base_url") or "").rstrip("/"),
        "docs_url": None,
        "models": [],
        "custom_provider": True,
    }


def enrich_catalog_with_custom(
    base: list[dict[str, Any]],
    providers_doc: dict[str, Any] | None = None,
) -> list[dict[str, Any]]:
    doc = providers_doc if providers_doc is not None else load_providers_doc()
    out = [dict(item) for item in base]
    seen = {str(item["id"]) for item in out}
    for pid, entry in doc.items():
        if pid in seen or not is_custom_provider_entry(entry):
            continue
        out.append(custom_catalog_entry(str(pid), entry))
        seen.add(str(pid))
    return out


def list_custom_provider_ids(providers_doc: dict[str, Any] | None = None) -> list[str]:
    doc = providers_doc if providers_doc is not None else load_providers_doc()
    return sorted(pid for pid, entry in doc.items() if is_custom_provider_entry(entry))


def create_custom_provider(
    *,
    provider_id: str,
    label: str,
    base_url: str,
    api_key: str = "",
) -> dict[str, Any]:
    from niannian.core.config import save_providers_config

    pid = validate_custom_provider_id(provider_id)
    url = (base_url or "").strip().rstrip("/")
    if not url:
        raise CustomProviderError("base_url 必填")
    name = (label or "").strip() or pid
    doc = load_providers_doc()
    if pid in doc and not is_custom_provider_entry(doc.get(pid)):
        raise CustomProviderError(f"provider_id 已占用: {pid}")
    doc[pid] = {
        "custom_provider": True,
        "label": name,
        "base_url": url,
        "api_key": (api_key or "").strip(),
    }
    save_providers_config(doc)
    return doc[pid]


def delete_custom_provider(provider_id: str) -> bool:
    from niannian.core.config import save_providers_config
    from niannian.llm.model_registry import load_model_registry, save_model_registry

    pid = validate_custom_provider_id(provider_id)
    doc = load_providers_doc()
    entry = doc.get(pid)
    if not is_custom_provider_entry(entry):
        raise CustomProviderError(f"非自定义 API 或不存在: {pid}")
    doc.pop(pid, None)
    save_providers_config(doc)

    models_doc = load_model_registry()
    pm = models_doc.get("provider_models")
    if isinstance(pm, dict) and pid in pm:
        pm.pop(pid, None)
        save_model_registry(models_doc)
    return True
