"""
HTTP客户端模块

实现HTTP请求功能，支持代理设置
"""

import json
import requests
from typing import Optional, Dict, Any, Union
from requests.exceptions import RequestException
from ..utils.error_codes import get_error_message


class Client:
    """
    HTTP客户端类

    用于发送HTTP请求到微信API
    """

    def __init__(self, proxy: Optional[str] = None):
        """
        初始化HTTP客户端

        :param proxy: 代理服务器地址，支持以下格式：
                      - HTTP代理: "http://ip:port"
                      - HTTPS代理: "https://ip:port"
                      - SOCKS5代理: "socks5://ip:port"
                      （使用SOCKS5代理需要安装 requests[socks] 依赖）
        """
        self.proxy = proxy
        self.session = requests.Session()
        # 设置默认请求头
        self.session.headers.update(
            {
                "Content-Type": "application/json; charset=utf-8",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            }
        )

    def _get_proxies(self) -> Optional[Dict[str, str]]:
        """
        获取代理配置

        :return: 代理配置字典
        """
        if self.proxy:
            return {"http": self.proxy, "https": self.proxy}
        return None

    def get(self, url: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        发送GET请求

        :param url: 请求URL
        :param params: 请求参数
        :return: 响应结果
        :raises RequestException: 请求失败时抛出异常
        """
        try:
            response = self.session.get(
                url=url, params=params, proxies=self._get_proxies(), timeout=30
            )
            response.raise_for_status()  # 检查响应状态码
            # 确保使用 UTF-8 编码来解码响应内容
            response.encoding = "utf-8"
            result = response.json()
            # 检查是否有错误
            if "errcode" in result and result["errcode"] != 0:
                error_msg = get_error_message(result["errcode"])
                print(f"[ERROR] API request failed: {error_msg} (code: {result['errcode']})")
            return result
        except RequestException as e:
            print(f"[ERROR] GET request failed: {url}, error: {str(e)}")
            raise

    def post(
        self, url: str, data: Optional[Union[Dict[str, Any], str]] = None
    ) -> Dict[str, Any]:
        """
        发送POST请求

        :param url: 请求URL
        :param data: 请求数据
        :return: 响应结果
        :raises RequestException: 请求失败时抛出异常
        """
        try:
            if isinstance(data, dict):
                data = json.dumps(data, ensure_ascii=False)
            response = self.session.post(
                url=url, data=data, proxies=self._get_proxies(), timeout=30
            )
            response.raise_for_status()
            response.encoding = "utf-8"
            result = response.json()
            # 检查是否有错误
            if "errcode" in result and result["errcode"] != 0:
                error_msg = get_error_message(result["errcode"])
                print(f"[ERROR] API request failed: {error_msg} (code: {result['errcode']})")
            return result
        except RequestException as e:
            print(f"[ERROR] POST request failed: {url}, error: {str(e)}")
            raise

    def upload(
        self, url: str, files: Dict[str, Any], data: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        上传文件

        :param url: 请求URL
        :param files: 文件数据，格式为 {"file": (filename, fileobj, content_type)}
        :param data: 其他请求数据
        :return: 响应结果
        :raises RequestException: 请求失败时抛出异常
        """
        try:
            # 临时移除Content-Type请求头，让requests库自动设置正确的multipart/form-data
            content_type = self.session.headers.pop("Content-Type", None)

            response = self.session.post(
                url=url, files=files, data=data, proxies=self._get_proxies(), timeout=60
            )
            response.raise_for_status()  # 检查响应状态码
            # 确保使用 UTF-8 编码来解码响应内容
            response.encoding = "utf-8"
            result = response.json()
            # 检查是否有错误
            if "errcode" in result and result["errcode"] != 0:
                error_msg = get_error_message(result["errcode"])
                print(f"[ERROR] API request failed: {error_msg} (code: {result['errcode']})")
            return result
        except RequestException as e:
            print(f"[ERROR] File upload failed: {url}, error: {str(e)}")
            raise
        finally:
            # 恢复Content-Type请求头
            if content_type:
                self.session.headers["Content-Type"] = content_type

    def download(self, url: str, params: Optional[Dict[str, Any]] = None) -> bytes:
        """
        下载文件

        :param url: 请求URL
        :param params: 请求参数
        :return: 文件内容
        :raises RequestException: 请求失败时抛出异常
        """
        try:
            response = self.session.get(
                url=url,
                params=params,
                proxies=self._get_proxies(),
                timeout=60,
                stream=True,
            )
            response.raise_for_status()  # 检查响应状态码
            return response.content
        except RequestException as e:
            print(f"[ERROR] File download failed: {url}, error: {str(e)}")
            raise
