"""
HTTP客户端工具模块

提供基础的HTTP请求封装，支持：
- GET/POST请求
- 自定义请求头
- 响应状态码验证
- CURL命令解析
"""
import logging
from typing import Optional, Dict, Any, Tuple

import requests

logger = logging.getLogger(__name__)


class HttpError(Exception):
    """
    HTTP请求异常类

    Attributes:
        code: 错误码
        message: 错误消息
    """

    def __init__(self, code: int = -200, message: str = ""):
        super().__init__(message)
        self.code = code
        self.message = message

    def __str__(self) -> str:
        return str({"code": self.code, "message": self.message})


class HttpClient:
    """
    HTTP客户端封装类

    提供GET和POST请求的静态方法，支持自定义请求头和参数。

    Example:
        >>> response = HttpClient.do_get("https://api.example.com/data")
        >>> response = HttpClient.do_post("https://api.example.com/data", params={"key": "value"})
    """

    HEADER_JSON = {"Content-Type": "application/json; charset=utf8"}
    HEADER_TEXT = {"Content-Type": "application/text; charset=utf8"}

    @staticmethod
    def _create_session(trust_env: bool = False) -> requests.Session:
        """
        创建请求会话。

        Args:
            trust_env: 是否继承环境变量中的代理、证书等配置。

        Returns:
            配置好的 requests.Session
        """
        session = requests.Session()
        session.trust_env = trust_env
        return session

    @staticmethod
    def do_get(
        url: str,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        logger: logging.Logger = logger,
        timeout: int = 1000,
        trust_env: bool = False,
        proxies: Optional[Dict[str, str]] = None
    ) -> Optional[str]:
        """
        发送GET请求

        Args:
            url: 请求URL
            params: 查询参数
            headers: 请求头
            logger: 日志记录器
            timeout: 超时时间（秒）
            trust_env: 是否继承环境变量中的代理配置，默认False（直连）
            proxies: 显式代理配置，默认None

        Returns:
            响应文本内容

        Raises:
            HttpError: HTTP响应状态码非200时抛出
        """
        logger.info(
            f"GET url: {url}; params: {params}; headers: {headers}; "
            f"trust_env: {trust_env}; proxies: {proxies}"
        )
        with HttpClient._create_session(trust_env=trust_env) as session:
            response = session.get(
                url,
                params=params,
                headers=headers,
                timeout=timeout,
                proxies=proxies
            )
        logger.info(f"GET url: {url}; response: {response.text[:500] if response.text else ''}")
        return HttpClient._parse_response(url, response)

    @staticmethod
    def do_post(
        url: str,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        logger: logging.Logger = logger,
        timeout: int = 1000,
        trust_env: bool = False,
        proxies: Optional[Dict[str, str]] = None
    ) -> Optional[str]:
        """
        发送POST请求（JSON格式）

        Args:
            url: 请求URL
            params: 请求体参数（将被序列化为JSON）
            headers: 请求头
            logger: 日志记录器
            timeout: 超时时间（秒）
            trust_env: 是否继承环境变量中的代理配置，默认False（直连）
            proxies: 显式代理配置，默认None

        Returns:
            响应文本内容

        Raises:
            HttpError: HTTP响应状态码非200时抛出
        """
        logger.info(
            f"POST url: {url}; params: {params}; headers: {headers}; "
            f"trust_env: {trust_env}; proxies: {proxies}"
        )
        with HttpClient._create_session(trust_env=trust_env) as session:
            response = session.post(
                url,
                json=params,
                headers=headers,
                timeout=timeout,
                proxies=proxies
            )
        logger.info(f"POST url: {url}; response: {response.text[:500] if response.text else ''}")
        return HttpClient._parse_response(url, response)

    @staticmethod
    def _parse_response(url: str, response: requests.Response) -> Optional[str]:
        """
        解析HTTP响应

        Args:
            url: 请求URL
            response: 响应对象

        Returns:
            响应文本内容

        Raises:
            HttpError: 响应状态码非200时抛出
        """
        if response is None:
            return None
        if response.status_code != 200:
            raise HttpError(
                code=response.status_code,
                message=f"HTTP接口响应异常：{url} | {response.status_code} | {response.reason}"
            )
        return response.text


class HttpUtil:
    """
    HTTP工具类

    提供CURL命令解析等辅助功能。
    """

    @staticmethod
    def format_curl(curl: str) -> Tuple[str, Dict[str, str]]:
        """
        解析CURL命令字符串

        Args:
            curl: CURL命令字符串

        Returns:
            (URL, 请求头字典)
        """
        url = ""
        headers: Dict[str, str] = {}

        curl_lines = curl.strip().split("-H ")
        for line in curl_lines:
            line = line.strip()
            if line.startswith("curl"):
                url = line.replace("curl ", "").replace("'", "").strip()
                continue

            header = line.replace("-H '", "").replace("'", "")
            if ": " not in header:
                continue
            key, value = header.split(": ", 1)
            # 跳过cookie
            if key.lower() == "cookie":
                continue
            headers[key.strip()] = value.strip()

        return url, headers

    @staticmethod
    def get_headers(curl: str) -> Dict[str, str]:
        """
        从CURL命令中提取请求头

        Args:
            curl: CURL命令字符串

        Returns:
            请求头字典
        """
        _, headers = HttpUtil.format_curl(curl)
        return headers

    @staticmethod
    def get_headers_default() -> Dict[str, str]:
        """
        获取默认的浏览器请求头

        Returns:
            模拟Chrome浏览器的请求头字典
        """
        curl = """
        curl 'http://example.com/' \\
        -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \\
        -H 'Accept-Language: zh-CN,zh;q=0.9' \\
        -H 'Connection: keep-alive' \\
        -H 'Upgrade-Insecure-Requests: 1' \\
        -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36' \\
        """
        _, headers = HttpUtil.format_curl(curl)
        return headers


if __name__ == "__main__":
    test_url = "https://www.baidu.com/"
    res = HttpClient.do_get(test_url)
    print(res[:200] if res else None)
