"""Backend API client for datasource APIs."""

import base64
import logging
import mimetypes
import os
from typing import Any, Dict, Optional
from urllib.parse import urlencode

import httpx

try:
    from .env_config import get_backend_base_url
except ImportError:
    from env_config import get_backend_base_url

logger = logging.getLogger(__name__)

DEFAULT_TOKEN = (
    ""
)

_SENSITIVE_FIELDS = {"password", "apiKey", "token", "secret"}


def _mask_secret(value: Optional[str]) -> str:
    """Mask a secret for logging, keeping only a few leading/trailing chars."""
    if not value:
        return "<空>"
    if len(value) <= 8:
        return "***"
    return f"{value[:4]}...{value[-4:]} (len={len(value)})"


class DataSourceAPIClient:
    """HTTP client for backend datasource APIs."""

    def __init__(
        self,
        base_url: Optional[str] = None,
        token: Optional[str] = None,
    ):
        self.base_url = (base_url or get_backend_base_url()).rstrip("/")
        # Prefer explicit token, then API_KEY env var, then built-in default.
        resolved = token or os.environ.get("API_KEY") or DEFAULT_TOKEN
        self.token = resolved.removeprefix("Bearer ").strip()
        self.client = httpx.Client(timeout=120.0)

    def close(self) -> None:
        """Close the underlying HTTP client."""
        self.client.close()

    def _get_headers(self, api_key: Optional[str] = None) -> Dict[str, str]:
        headers = {
            "Authorization": f"Bearer {self.token}",
            "Accept": "application/json",
        }
        if api_key:
            headers["X-Datasource-API-Key"] = api_key
        return headers

    @staticmethod
    def _sanitize_value(value: Any) -> Any:
        """Redact sensitive nested values for logging."""
        if isinstance(value, dict):
            return {
                k: "***" if k in _SENSITIVE_FIELDS else DataSourceAPIClient._sanitize_value(v)
                for k, v in value.items()
            }
        if isinstance(value, list):
            return [DataSourceAPIClient._sanitize_value(item) for item in value]
        return value

    @staticmethod
    def _file_tuple(file_path: str) -> tuple:
        """Build a multipart file tuple with filename and content type."""
        filename = os.path.basename(file_path)
        content_type, _ = mimetypes.guess_type(filename)
        if content_type is None:
            content_type = "application/octet-stream"
        return (filename, open(file_path, "rb"), content_type)

    def request(
        self,
        method: str,
        path_template: str,
        path_params: Optional[Dict[str, Any]] = None,
        query_params: Optional[Dict[str, Any]] = None,
        body: Optional[Dict[str, Any]] = None,
        file_path: Optional[str] = None,
        api_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Send a request and return JSON response."""
        path_params = path_params or {}
        query_params = query_params or {}

        try:
            url = self._build_url(path_template, path_params, query_params)
            headers = self._get_headers(api_key)

            safe_body = self._sanitize_value(body) if body else body
            logger.info(f"调用后端 API: {method} {url}")
            logger.info(
                f"请求密钥 - X-Datasource-API-Key: {_mask_secret(api_key)}, "
                f"Authorization token: {_mask_secret(self.token)}"
            )
            logger.debug(
                f"path_params={path_params}, query_params={query_params}, "
                f"body={safe_body}, file_path={file_path}"
            )

            method = method.upper()
            if method == "GET":
                response = self.client.get(url, headers=headers)
            elif method == "DELETE":
                if body is not None:
                    headers["Content-Type"] = "application/json"
                    response = self.client.request(method, url, headers=headers, json=body)
                else:
                    response = self.client.delete(url, headers=headers)
            elif file_path:
                # Multipart upload
                headers.pop("Content-Type", None)
                file_tuple = self._file_tuple(file_path)
                files = {"file": file_tuple}
                try:
                    response = self.client.request(
                        method, url, headers=headers, data=body, files=files
                    )
                finally:
                    file_tuple[1].close()
            elif body is not None:
                headers["Content-Type"] = "application/json"
                response = self.client.request(method, url, headers=headers, json=body)
            else:
                response = self.client.request(method, url, headers=headers)

            response.raise_for_status()
            content_type = response.headers.get("content-type", "")
            if "application/json" in content_type:
                data = response.json()
            else:
                # Non-JSON response (e.g., Excel export), encode as base64
                data = {
                    "success": True,
                    "contentType": content_type,
                    "fileBase64": base64.b64encode(response.content).decode("ascii"),
                    "message": "后端返回非 JSON 内容，已使用 base64 编码",
                }
            logger.info(f"后端 API 调用成功: {method} {url}")
            logger.debug(f"响应: {data}")
            return data

        except httpx.TimeoutException as e:
            error_msg = f"API 请求超时: {method} {path_template}"
            logger.error(error_msg)
            raise Exception(error_msg) from e
        except httpx.HTTPStatusError as e:
            error_msg = f"API 请求失败 (HTTP {e.response.status_code}): {e.response.text}"
            logger.error(error_msg)
            raise Exception(error_msg) from e
        except httpx.RequestError as e:
            error_msg = f"API 请求异常: {method} {path_template}, 错误: {e}"
            logger.error(error_msg)
            raise Exception(error_msg) from e
        except Exception as e:
            error_msg = f"处理 API 响应时出错: {e}"
            logger.error(error_msg, exc_info=True)
            raise Exception(error_msg) from e

    def _build_url(
        self,
        path_template: str,
        path_params: Dict[str, Any],
        query_params: Dict[str, Any],
    ) -> str:
        path = path_template
        for key, value in path_params.items():
            path = path.replace(f"{{{key}}}", str(value))

        url = f"{self.base_url}{path}"

        if query_params:
            filtered = {k: v for k, v in query_params.items() if v is not None}
            if filtered:
                url = f"{url}?{urlencode(filtered)}"

        return url


def api_request(
    method: str,
    path_template: str,
    path_params: Optional[Dict[str, Any]] = None,
    query_params: Optional[Dict[str, Any]] = None,
    body: Optional[Dict[str, Any]] = None,
    file_path: Optional[str] = None,
    api_key: Optional[str] = None,
    base_url: Optional[str] = None,
    token: Optional[str] = None,
) -> Dict[str, Any]:
    """Convenience wrapper for one-off API requests."""
    client = DataSourceAPIClient(base_url=base_url, token=token)
    try:
        return client.request(
            method=method,
            path_template=path_template,
            path_params=path_params,
            query_params=query_params,
            body=body,
            file_path=file_path,
            api_key=api_key,
        )
    finally:
        client.close()


# Module-level default client
_default_client = DataSourceAPIClient()


def get_default_client() -> DataSourceAPIClient:
    return _default_client
