"""
Base REST client helpers for direct exchange connections.

Notes:
- Keep this minimal and dependency-light (requests only).
- All secrets must be excluded from logs.
"""

from __future__ import annotations

import json
import logging
import os
import time
from dataclasses import dataclass
from typing import Any, Dict, Optional, Tuple, Union

import requests

logger = logging.getLogger(__name__)

# Cached SSL verify setting for all live-trading REST calls (requests + SOCKS proxy).
_requests_verify_value: Optional[Union[bool, str]] = None
_ssl_verify_disabled_logged = False

# OS CA bundles (Docker / slim images: install ``ca-certificates``; corporate roots often added here too).
_SYSTEM_CA_BUNDLE_CANDIDATES: Tuple[str, ...] = (
    "/etc/ssl/certs/ca-certificates.crt",  # Debian/Ubuntu
    "/etc/ssl/cert.pem",  # Alpine, some slim images
    "/etc/pki/tls/certs/ca-bundle.crt",  # RHEL/Fedora
)


def _get_requests_verify() -> Union[bool, str]:
    """
    Resolve ``verify`` for ``requests`` when calling exchanges through proxies (e.g. PROXY_URL=socks5h://...).

    - LIVE_TRADING_SSL_VERIFY=0|false|no|off: disable verification (insecure; mitm risk).
    - LIVE_TRADING_CA_BUNDLE / REQUESTS_CA_BUNDLE / SSL_CERT_FILE / CURL_CA_BUNDLE: path to a PEM CA bundle
      (needed for corporate TLS inspection or custom roots).
    - Else a non-empty OS CA file if present (helps Gate/HTX/hbdm etc. in minimal images).
    - Otherwise certifi's bundle when available.
    """
    global _requests_verify_value, _ssl_verify_disabled_logged
    if _requests_verify_value is not None:
        return _requests_verify_value

    flag = (os.environ.get("LIVE_TRADING_SSL_VERIFY") or "").strip().lower()
    if flag in ("0", "false", "no", "off"):
        if not _ssl_verify_disabled_logged:
            logger.warning(
                "LIVE_TRADING_SSL_VERIFY is disabled: HTTPS certificate verification is OFF for live trading "
                "requests (MITM risk). Fix CA trust or set LIVE_TRADING_CA_BUNDLE instead for production."
            )
            _ssl_verify_disabled_logged = True
        _requests_verify_value = False
        return _requests_verify_value

    for key in ("LIVE_TRADING_CA_BUNDLE", "REQUESTS_CA_BUNDLE", "SSL_CERT_FILE", "CURL_CA_BUNDLE"):
        path = (os.environ.get(key) or "").strip()
        if path and os.path.isfile(path):
            _requests_verify_value = path
            return _requests_verify_value

    for path in _SYSTEM_CA_BUNDLE_CANDIDATES:
        try:
            if path and os.path.isfile(path) and os.path.getsize(path) >= 256:
                _requests_verify_value = path
                return _requests_verify_value
        except OSError:
            continue

    try:
        import certifi

        _requests_verify_value = certifi.where()
    except ImportError:
        _requests_verify_value = True
    return _requests_verify_value


@dataclass
class LiveOrderResult:
    exchange_id: str
    exchange_order_id: str
    filled: float
    avg_price: float
    raw: Dict[str, Any]


class LiveTradingError(Exception):
    pass


class BaseRestClient:
    def __init__(self, base_url: str, timeout_sec: float = 15.0):
        self.base_url = (base_url or "").rstrip("/")
        self.timeout_sec = float(timeout_sec)

    def _url(self, path: str) -> str:
        p = str(path or "")
        if not p.startswith("/"):
            p = "/" + p
        return f"{self.base_url}{p}"

    def _request(
        self,
        method: str,
        path: str,
        *,
        params: Optional[Dict[str, Any]] = None,
        json_body: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        data: Optional[Any] = None,
    ) -> Tuple[int, Dict[str, Any], str]:
        url = self._url(path)
        try:
            resp = requests.request(
                method=str(method or "GET").upper(),
                url=url,
                params=params or None,
                json=json_body if json_body is not None else None,
                data=data,
                headers=headers or None,
                timeout=self.timeout_sec,
                verify=_get_requests_verify(),
            )
        except UnicodeEncodeError as e:
            # requests/http.client requires header values to be latin-1 encodable.
            # This usually means user pasted API keys/passphrases containing non-ASCII characters,
            # or included invisible whitespace/newlines.
            raise LiveTradingError(
                "Auth failed: request headers contain non-ASCII characters and cannot be encoded. "
                "Please re-enter API key/secret/passphrase (ASCII only; no Chinese characters, smart quotes, "
                "full-width symbols, newlines, or trailing spaces). "
                f"Original error: {e}"
            )
        except requests.exceptions.SSLError as e:
            logger.warning(
                "Exchange HTTPS TLS verify failed (%s). Same setting applies to all REST exchanges (Gate, HTX/hbdm, etc.). "
                "Behind PROXY_URL/SOCKS or TLS inspection: set LIVE_TRADING_CA_BUNDLE to a PEM bundle (or REQUESTS_CA_BUNDLE), "
                "ensure ca-certificates in the image, or dev-only LIVE_TRADING_SSL_VERIFY=false. %s",
                url,
                e,
            )
            raise
        text = resp.text or ""
        parsed: Dict[str, Any] = {}
        try:
            parsed = resp.json() if text else {}
        except Exception:
            parsed = {"raw_text": text[:2000]}
        return int(resp.status_code), parsed, text

    @staticmethod
    def _now_ms() -> int:
        return int(time.time() * 1000)

    @staticmethod
    def _json_dumps(obj: Any) -> str:
        return json.dumps(obj, ensure_ascii=False, separators=(",", ":"))

    def get_fee_rate(self, symbol: str, market_type: str = "swap") -> Optional[Dict[str, float]]:
        """Query account fee rate from exchange. Returns {"maker": 0.0002, "taker": 0.0005} or None."""
        return None


