"""Ontology HTTP API client - 优雅的 curl 封装"""

from __future__ import annotations

from itertools import count
from typing import Any

import requests
from pydantic import BaseModel, Field

from ..utils.log_utils import logger
from .config import get_ontology_config, get_workspace_id


class OntologyResponse(BaseModel):
    """Ontology API 响应"""

    code: str = Field(..., description="响应码")
    message: str = Field(default="", description="响应消息")
    result: dict[str, Any] | None = Field(default=None, description="结果数据")


_REQUEST_ID_COUNTER = count(1)


class OntologyService:
    """Ontology HTTP 客户端 - 优雅的 curl 封装

    只负责发送 HTTP 请求，用户自己构造 DSL
    """

    def __init__(
        self,
        endpoint: str | None = None,
        token: str | None = None,
        workspace_id: str | None = None,
        timeout: int = 30,
    ) -> None:
        """初始化客户端

        优先使用参数，其次从环境变量读取 ServiceConfig：
        - ServiceConfig.ontology.endpoint: Ontology API base URL
        - ServiceConfig.ontology.token: Authorization token
        - ServiceConfig.workspaceId: Workspace ID

        Args:
            endpoint: Ontology API base URL（如 http://10.57.173.55:8008）
            token: Authorization token
            workspace_id: 工作空间 ID
            timeout: 请求超时时间（秒）

        Raises:
            ValueError: 当必需的配置参数缺失时

        Examples:
            >>> # 从环境变量读取
            >>> client = OntologyService()

            >>> # 显式传参
            >>> client = OntologyService(
            ...     endpoint="http://10.57.173.55:8008",
            ...     token="bce-auth-v1/..."
            ... )
        """
        self.x_bce_access_key: str | None = None
        self.x_bce_security_key: str | None = None
        self.x_bce_security_token: str | None = None

        if endpoint and token:
            self.endpoint = endpoint
            self.token = token
        else:
            config = get_ontology_config()
            if config is None:
                raise RuntimeError("require ontology config")
            self.endpoint = endpoint or config.endpoint
            self.token = token or config.token
            self.x_bce_access_key = (config.bceAccessKey or "").strip() or None
            self.x_bce_security_key = (config.bceSecurityKey or "").strip() or None
            self.x_bce_security_token = (config.bceSecurityToken or "").strip() or None
        self.workspace_id = workspace_id or get_workspace_id()
        self.timeout = timeout

        if not self.endpoint:
            raise ValueError("必须提供 ontology endpoint")
        if not self.token:
            raise ValueError("必须提供 ontology token")
        if not self.workspace_id:
            raise ValueError("必须提供 workspace_id")

        logger.debug(f"Ontology service initialized: endpoint={self.endpoint}")

    def search(
        self,
        dsl: dict[str, Any],
    ) -> OntologyResponse:
        """执行 Ontology 对象搜索

        Args:
            dsl: 完整的 DSL 查询字典（必须包含 ontology 和 apiName）

        Returns:
            Ontology 响应

        Raises:
            RuntimeError: 当 API 调用失败时

        Examples:
            >>> client = OntologyService()
            >>> dsl = {
            ...     "ontology": "whb_demo01",
            ...     "apiName": "ltwDemoUniqueObject",
            ...     "limit": 5,
            ...     "where": {
            ...         "type": "and",
            ...         "filter": [{"type": "eq", "field": "name", "value": "name-71"}]
            ...     }
            ... }
            >>> response = client.search(dsl=dsl)
            >>> print(response.code)  # "SUCCESS"
            >>> print(len(response.result["data"]))  # 5
        """
        # 构建完整的 DSL（补充 ontology 和 apiName，DSL 优先）
        if not dsl:
            raise ValueError("dsl 不能为空")

        full_dsl = dict(dsl)
        ontology = full_dsl.get("ontology")
        api_name = full_dsl.get("apiName")
        if not ontology or not api_name:
            raise ValueError("dsl 必须包含 ontology 和 apiName")

        workspace_id = self.workspace_id
        if not workspace_id:
            raise ValueError("workspace_id 未配置")

        base_endpoint = self.endpoint.rstrip("/")
        ontology_container = f"workspace_{ontology}_ontology"
        url = f"{base_endpoint}/v1/workspaces/{workspace_id}/ontologies/{ontology_container}/objects/{api_name}/search"

        headers = {
            "Content-Type": "application/x-ndjson",
            "Authorization": self.token,
            "X-Bce-Request-Id": str(next(_REQUEST_ID_COUNTER)),
        }
        if self.x_bce_access_key:
            headers["x-bce-access-key"] = self.x_bce_access_key
            headers["x-bce-security-key"] = self.x_bce_security_key or ""
            headers["x-bce-security-token"] = self.x_bce_security_token or ""

        try:
            logger.debug(f"POST {url}")
            resp = requests.post(url, headers=headers, json=full_dsl, timeout=self.timeout)
            resp.raise_for_status()

            data = resp.json()
            # logger.debug(f"Response code: {data.get('code')}")

            response = OntologyResponse(**data)
            if response.code != "SUCCESS":
                logger.error(f"POST {url}")
                logger.error(f"DSL: {full_dsl}")
                raise RuntimeError(f"Ontology API 业务错误: {response.message} (code: {response.code})")

            return response

        except requests.Timeout as e:
            logger.error(f"Ontology API 请求超时: {e}")
            logger.error(f"POST {url}")
            logger.error(f"DSL: {full_dsl}")
            raise RuntimeError(f"Ontology API 请求超时 ({self.timeout}s): {e}")
        except requests.RequestException as e:
            logger.error(f"Ontology API 调用失败: {e}")
            logger.error(f"POST {url}")
            logger.error(f"DSL: {full_dsl}")
            raise RuntimeError(f"Ontology API 调用失败: {e}")
        except Exception as e:
            logger.error(f"处理 Ontology 响应失败 ({type(e).__name__}): {e}")
            logger.error(f"POST {url}")
            logger.error(f"DSL: {full_dsl}")
            raise RuntimeError(f"处理 Ontology 响应失败 ({type(e).__name__}): {e}")


# 工厂函数（保持架构一致性）
def create_ontology_service(**kwargs: Any) -> OntologyService:
    """创建 Ontology 客户端

    Args:
        **kwargs: 配置参数（endpoint, token, timeout 等）

    Returns:
        OntologyService 实例

    Examples:
        >>> # 方式1: 从环境变量读取
        >>> client = create_ontology_service()

        >>> # 方式2: 显式传参
        >>> client = create_ontology_service(
        ...     endpoint="http://10.57.173.55:8008",
        ...     token="bce-auth-v1/...",
        ... )
    """
    return OntologyService(**kwargs)
