"""
核心服务器模块

提供API调用、认证处理、配置管理等核心功能
"""

import asyncio
import json
import os
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Union
from urllib.parse import urljoin

import httpx

from .api_auth_service import AuthService
from ..util.logger_config import get_logger

# 获取日志器
logger = get_logger(__name__)


class ApiError(Exception):
    """API调用相关异常"""

    def __init__(self, message: str, status_code: Optional[int] = None):
        super().__init__(message)
        self.status_code = status_code


class ResponseSaver:
    """响应数据保存管理器"""

    def __init__(self, save_dir: str = "lzwcai_mcp_dyntoolapi_log_call_api"):
        """
        初始化响应保存器

        Args:
            save_dir: 保存目录路径
        """
        self.save_dir = Path(save_dir)
        self.save_dir.mkdir(exist_ok=True)
        logger.debug(f"响应保存目录: {self.save_dir.absolute()}")

    def save_response(
        self,
        response_data: Dict[str, Any],
        api_url: str,
        method: str = "GET",
        request_data: Optional[Dict[str, Any]] = None,
    ) -> str:
        """
        保存API响应到本地JSON文件

        Args:
            response_data: 响应数据
            api_url: API URL
            method: HTTP方法
            request_data: 请求数据

        Returns:
            保存的文件路径
        """
        try:
            # 生成文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]  # 精确到毫秒
            safe_url = self._sanitize_filename(api_url)
            filename = f"{timestamp}_{method}_{safe_url}.json"
            file_path = self.save_dir / filename

            # 构建保存的数据结构
            save_data = {
                "timestamp": datetime.now().isoformat(),
                "api_info": {
                    "url": api_url,
                    "method": method.upper(),
                },
                "request_data": request_data or {},
                "response_data": response_data,
                "metadata": {
                    "saved_at": datetime.now().isoformat(),
                    "file_name": filename,
                }
            }

            # 保存到文件
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(save_data, f, ensure_ascii=False, indent=2)

            logger.info(f"API响应已保存到: {file_path}")
            return str(file_path)

        except Exception as e:
            logger.error(f"保存API响应失败: {str(e)}")
            return ""

    def _sanitize_filename(self, url: str) -> str:
        """
        清理URL以生成安全的文件名

        Args:
            url: 原始URL

        Returns:
            清理后的文件名部分
        """
        # 移除协议和域名，只保留路径
        if "://" in url:
            url = url.split("://", 1)[1]
        if "/" in url:
            url = url.split("/", 1)[1] if "/" in url else url

        # 替换特殊字符
        safe_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
        sanitized = "".join(c if c in safe_chars else "_" for c in url)

        # 限制长度
        return sanitized[:50] if len(sanitized) > 50 else sanitized


class ConfigManager:
    """配置管理器"""

    @staticmethod
    def load_api_config(file_path: str = "generator_api.json") -> Dict[str, Any]:
        """
        加载API配置文件

        Args:
            file_path: JSON配置文件路径

        Returns:
            解析后的API配置字典

        Raises:
            FileNotFoundError: 文件不存在
            json.JSONDecodeError: JSON格式错误
        """
        logger.debug(f"尝试加载配置文件: {file_path}")

        try:
            with open(file_path, "r", encoding="utf-8") as file:
                config = json.load(file)
            logger.info(f"成功加载配置文件: {file_path}")
            logger.debug(f"配置内容: {config}")
            return config
        except FileNotFoundError:
            logger.error(f"配置文件未找到: {file_path}")
            raise FileNotFoundError(f"配置文件未找到: {file_path}")
        except json.JSONDecodeError as e:
            logger.error(f"配置文件JSON格式错误: {file_path} - {str(e)}")
            raise json.JSONDecodeError(
                f"配置文件JSON格式错误: {file_path} - {str(e)}", e.doc, e.pos
            )


class UserManager:
    """用户管理器"""

    @staticmethod
    def get_user_id_from_env() -> Tuple[bool, Optional[str]]:
        """
        从环境变量中获取用户ID

        Returns:
            tuple: (是否成功获取, 用户ID值)
        """
        try:
            user_id = os.environ.get("userId")
            if user_id:
                logger.debug(f"从环境变量获取用户ID: {user_id}")
                return True, user_id
            logger.debug("环境变量中未找到用户ID")
            return False, None
        except Exception as e:
            logger.warning(f"获取环境变量用户ID时发生异常: {e}")
            return False, None

    @staticmethod
    def extract_user_id_from_request(
        request_data: Dict[str, Any], is_grouped_format: bool
    ) -> Optional[str]:
        """
        从请求数据中提取用户ID

        Args:
            request_data: 请求数据
            is_grouped_format: 是否为分组格式

        Returns:
            用户ID或None
        """
        # 优先从请求数据中获取userId
        if isinstance(request_data, dict):
            if is_grouped_format:
                # 按优先级顺序查找：lzwcaiConfig > header > body > userId（兼容旧版本）
                user_id = (
                    request_data.get("lzwcaiConfig", {}).get("userId")
                    or request_data.get("header", {}).get("userId")
                    or request_data.get("body", {}).get("userId")
                    or (request_data.get("userId") or {}).get("userId")
                )
                if user_id:
                    logger.info(f"从请求数据中获取到用户ID: {user_id}")
                    return user_id
            else:
                # 非分组格式：优先从lzwcaiConfig获取，然后是userId（兼容旧版本）
                user_id = (
                    (request_data.get("lzwcaiConfig") or {}).get("userId")
                    or (request_data.get("userId") or {}).get("userId")
                )
                if user_id:
                    logger.info(f"从请求数据中获取到用户ID: {user_id}")
                    return user_id

        # 如果请求数据中没有userId，则从环境变量获取作为备用
        success, env_user_id = UserManager.get_user_id_from_env()
        if success:
            logger.info(f"从环境变量获取到用户ID: {env_user_id}")
            return env_user_id

        logger.warning("未能从请求数据或环境变量中获取到用户ID")
        return None


class HeaderProcessor:
    """请求头处理器"""

    @staticmethod
    def validate_header_value(value: Any) -> str:
        """
        验证并标准化请求头值

        Args:
            value: 原始值

        Returns:
            标准化后的字符串值
        """
        if value is None:
            return ""
        return str(value).strip()

    @staticmethod
    def process_auth_headers(
        base_headers: Dict[str, Any],
        request_data: Dict[str, Any],
        auth_token: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, str]:
        """
        处理认证头信息

        Args:
            base_headers: 基础请求头
            request_data: 请求数据
            auth_token: 认证token信息

        Returns:
            处理后的请求头字典

        Raises:
            ValueError: 当base_headers不是字典类型时
        """
        if not isinstance(base_headers, dict):
            raise ValueError("base_headers必须是字典类型")

        if not isinstance(request_data, dict):
            request_data = {}

        if auth_token is None:
            auth_token = {}

        # 获取请求数据中的header部分
        request_headers = request_data.get("header", {})

        # 按优先级合并headers: base < request < auth_token
        processed_headers = {}

        # 1. 基础headers (key转为小写以避免重复)
        for key, value in base_headers.items():
            processed_headers[key.lower()] = HeaderProcessor.validate_header_value(value)

        # 2. 请求中的headers (key转为小写以避免重复)
        for key, value in request_headers.items():
            processed_headers[key.lower()] = HeaderProcessor.validate_header_value(value)

        # 3. 认证token headers (最高优先级, key转为小写以避免重复)
        for key, value in auth_token.items():
            processed_headers[key.lower()] = HeaderProcessor.validate_header_value(value)

        return processed_headers


class RequestBuilder:
    """请求构建器"""

    @staticmethod
    def is_grouped_format(request_data: Dict[str, Any]) -> bool:
        """
        检查请求数据是否为分组格式

        Args:
            request_data: 请求数据

        Returns:
            是否为分组格式
        """
        return any(
            key in ["header", "path", "query", "body", "params", "form", "formdata"]
            for key in request_data.keys()
        )

    @staticmethod
    def build_url_with_path_params(base_url: str, path_params: Dict[str, Any]) -> str:
        """
        使用路径参数构建URL

        Args:
            base_url: 基础URL
            path_params: 路径参数

        Returns:
            替换路径参数后的URL
        """
        url = base_url
        for key, value in path_params.items():
            placeholder = f"{{{key}}}"
            if placeholder in url:
                url = url.replace(placeholder, str(value))
        return url

    @staticmethod
    def extract_parameters_from_grouped_format(
        request_data: Dict[str, Any], method: str
    ) -> Tuple[
        Dict[str, Any],
        Dict[str, Any],
        Optional[Dict[str, Any]],
        Optional[Dict[str, Any]],
        Optional[Dict[str, Any]],
    ]:
        """
        从分组格式请求数据中提取参数

        Args:
            request_data: 请求数据
            method: HTTP方法

        Returns:
            (path_params, query_params, json_data, form_data, formdata_data)
        """
        path_params = {}
        query_params = {}
        json_data = None
        form_data = None
        formdata_data = None

        # 处理路径参数
        if "path" in request_data:
            path_params.update(request_data["path"])

        # 兼容params命名（与path含义相同）
        if "params" in request_data:
            path_params.update(request_data["params"])

        # 处理查询参数
        if "query" in request_data:
            query_params.update(request_data["query"])

        # 处理请求体数据
        if "body" in request_data and method.upper() in ["POST", "PUT", "PATCH"]:
            json_data = request_data["body"]

        if "form" in request_data and method.upper() in ["POST", "PUT", "PATCH"]:
            form_data = request_data["form"]

        if "formdata" in request_data and method.upper() in ["POST", "PUT", "PATCH"]:
            formdata_data = request_data["formdata"]

        return path_params, query_params, json_data, form_data, formdata_data

    @staticmethod
    def extract_parameters_from_flat_format(
        request_data: Dict[str, Any], parameters: List[Dict[str, Any]], method: str
    ) -> Tuple[
        Dict[str, str],
        Dict[str, Any],
        Dict[str, Any],
        Optional[Dict[str, Any]],
        Optional[Dict[str, Any]],
        Optional[Dict[str, Any]],
    ]:
        """
        从扁平格式请求数据中提取参数

        Args:
            request_data: 请求数据
            parameters: 参数配置列表
            method: HTTP方法

        Returns:
            (headers, path_params, query_params, json_data, form_data, formdata_data)
        """
        headers = {}
        path_params = {}
        query_params = {}
        json_data = None
        form_data = None  # for application/x-www-form-urlencoded
        formdata_data = None  # for multipart/form-data

        for param in parameters:
            param_name = param.get("paramName")
            request_type = param.get("requestType")
            default_value = param.get("defaultValue")

            # 获取参数值：优先使用请求数据中的值，否则使用默认值
            if param_name in request_data:
                param_value = request_data[param_name]
                # 如果传入的值为None或空字符串，且有默认值，则使用默认值
                if param_value in (None, "") and default_value is not None:
                    param_value = default_value
            else:
                param_value = default_value

            # 如果参数没有值且不是必需的，则跳过
            if param_value is None and param.get("required", 0) == 0:
                continue

            # 根据请求类型分配参数
            if request_type == "header":
                headers[param_name] = (
                    str(param_value) if param_value is not None else ""
                )
            elif request_type == "query":
                if param_value is not None:
                    query_params[param_name] = param_value
            elif request_type in ["params", "path"]:
                if param_value is not None:
                    path_params[param_name] = param_value
            elif request_type == "body" and method.upper() in ["POST", "PUT", "PATCH"]:
                if json_data is None:
                    json_data = {}
                json_data[param_name] = param_value
            elif request_type == "form" and method.upper() in ["POST", "PUT", "PATCH"]:
                if form_data is None:
                    form_data = {}
                form_data[param_name] = param_value
            elif request_type == "formdata" and method.upper() in ["POST", "PUT", "PATCH"]:
                if formdata_data is None:
                    formdata_data = {}
                formdata_data[param_name] = param_value

        return headers, path_params, query_params, json_data, form_data, formdata_data


class ApiClient:
    """API客户端"""

    def __init__(self, timeout: int = 30, verify: bool = True, save_responses: bool = True, save_dir: str = "lzwcai_mcp_dyntoolapi_log_call_api"):
        """
        初始化API客户端

        Args:
            timeout: 请求超时时间（秒）
            verify: 是否验证SSL证书
            save_responses: 是否保存响应到本地JSON文件
            save_dir: 响应保存目录
        """
        self.timeout = timeout
        self.verify = verify
        self.save_responses = save_responses
        self.auth_service = AuthService()

        # 初始化响应保存器
        if self.save_responses:
            self.response_saver = ResponseSaver(save_dir)
            logger.info(f"已启用响应保存功能，保存目录: {save_dir}")
        else:
            self.response_saver = None
            logger.info("响应保存功能已禁用")

    async def call_api(
        self,
        api_config: Dict[str, Any],
        request_data: Optional[Dict[str, Any]] = None,
        need_auth: bool = True,
    ) -> Dict[str, Any]:
        """
        通用API调用方法

        Args:
            api_config: API配置信息
            request_data: 请求数据，支持扁平格式和分组格式
            need_auth: 是否需要认证

        Returns:
            API响应结果

        Raises:
            ApiError: API调用相关错误
            ValueError: 配置或参数错误
        """
        api_url = api_config.get("apiUrl", "N/A")
        logger.info(f"开始API调用: {api_url}")
        logger.debug(f"需要认证: {need_auth}")
        logger.debug(f"请求数据: {request_data}")

        # 验证API配置
        self._validate_api_config(api_config)

        # 准备基础信息
        domain_url = api_config["domainUrl"]
        api_url = api_config["apiUrl"]
        method = api_config.get("method", "GET")

        # 构建完整URL
        full_url = urljoin(domain_url.rstrip("/") + "/", api_url.lstrip("/"))
        logger.debug(f"完整URL: {full_url}")
        logger.debug(f"HTTP方法: {method}")

        # 初始化请求参数
        headers = {}
        query_params = {}
        path_params = {}
        json_data = None
        form_data = None
        formdata_data = None

        request_data = request_data or {}
        parameters = api_config.get("parameters", [])
        logger.debug(f"参数配置数量: {len(parameters)}")

        # 检查请求数据格式
        is_grouped = RequestBuilder.is_grouped_format(request_data)
        logger.debug(f"请求数据格式 - 分组格式: {is_grouped}")

        # 处理认证
        if need_auth:
            logger.debug("开始处理认证")
            auth_headers = await self._handle_authentication(
                request_data, api_config, is_grouped
            )
            headers.update(auth_headers)
            logger.debug(f"认证头信息: {auth_headers}")
        else:
            logger.debug("跳过认证")

        # 提取参数
        if is_grouped:
            (path_params, query_params, json_data, form_data, formdata_data) = (
                RequestBuilder.extract_parameters_from_grouped_format(
                    request_data, method
                )
            )
        else:
            (
                param_headers,
                path_params,
                query_params,
                json_data,
                form_data,
                formdata_data,
            ) = RequestBuilder.extract_parameters_from_flat_format(
                request_data, parameters, method
            )
            headers.update(param_headers)

        logger.info(f"请求头: {headers},request_data: {request_data}")
        # 处理请求头
        headers = HeaderProcessor.process_auth_headers(headers, request_data)
        # 替换URL中的路径参数
        if path_params:
            full_url = RequestBuilder.build_url_with_path_params(full_url, path_params)

        # 根据请求体内容设置Content-Type (如果未被显式设置)
        # 注意：httpx 会自动处理某些 Content-Type，但显式设置可以避免歧义
        if "content-type" not in headers:
            if json_data is not None:
                headers["content-type"] = "application/json"
            elif form_data is not None:
                # application/x-www-form-urlencoded 类型
                headers["content-type"] = "application/x-www-form-urlencoded"
            elif formdata_data is not None:
                # multipart/form-data 类型 - 不设置 Content-Type，让 httpx 自动添加 boundary
                # 如果手动设置会缺少 boundary 参数导致请求失败
                pass

        # 发送请求
        logger.info(f"发送HTTP请求: {method} {full_url}")

        # 记录重要的请求信息（INFO级别，便于调试）
        if headers:
            # 过滤敏感信息，只显示关键头部
            safe_headers = {}
            for key, value in headers.items():
                if key.lower() in ['authorization', 'x-api-key', 'token']:
                     safe_headers[key] = value
                else:
                    safe_headers[key] = value
            logger.info(f"请求头: {safe_headers}")

        if query_params:
            logger.info(f"查询参数: {query_params}")

        if json_data:
            logger.info(f"请求体 (JSON): {json_data}")
        if form_data:
            logger.info(f"请求体 (Form): {form_data}")
        if formdata_data:
            logger.info(f"请求体 (FormData): {formdata_data}")

        # 详细的调试信息仍保留在DEBUG级别
        logger.debug(f"完整请求头: {headers}")
        logger.debug(f"完整查询参数: {query_params}")
        logger.debug(f"完整请求体 (JSON): {json_data}")
        logger.debug(f"完整请求体 (Form): {form_data}")
        logger.debug(f"完整请求体 (FormData): {formdata_data}")

        # 发送请求并获取响应
        response = await self._send_request(
            method, full_url, headers, query_params, json_data, form_data, formdata_data
        )

        # 保存响应到本地JSON文件
        if self.save_responses and self.response_saver:
            try:
                saved_path = self.response_saver.save_response(
                    response_data=response,
                    api_url=full_url,
                    method=method,
                    request_data=request_data
                )
                if saved_path:
                    logger.info(f"响应已保存到: {saved_path}")
            except Exception as e:
                logger.error(f"保存响应失败: {str(e)}")

        return response

    def _validate_api_config(self, api_config: Dict[str, Any]) -> None:
        """验证API配置"""
        logger.debug("验证API配置")

        if not api_config:
            logger.error("API配置为空")
            raise ValueError("API配置不能为空")

        if not api_config.get("domainUrl") or not api_config.get("apiUrl"):
            logger.error(f"缺少必要配置项 - domainUrl: {api_config.get('domainUrl')}, apiUrl: {api_config.get('apiUrl')}")
            raise ValueError("缺少必要的API配置项：domainUrl或apiUrl")

        logger.debug("API配置验证通过")

    async def _handle_authentication(
        self, request_data: Dict[str, Any], api_config: Dict[str, Any], is_grouped: bool
    ) -> Dict[str, str]:
        """处理认证逻辑"""
        user_id = UserManager.extract_user_id_from_request(request_data, is_grouped)
        biz_sys_id = api_config.get("bizSysId")

        auth_result = await self.auth_service.authorize_request(user_id, biz_sys_id)

        if not auth_result["success"]:
            raise ApiError(
                f"认证失败: {auth_result.get('error_response', {})}",
                auth_result.get("error_response", {}).get("status_code"),
            )

        token_header = auth_result.get("tokenHeader", {})
        logger.info(f"API调用获取到Token - 用户ID: {user_id}, 业务系统ID: {biz_sys_id}, Token: {token_header}")
        return token_header


    def _contains_file(self, data: Dict[str, Any]) -> bool:
        """
        检查数据字典中是否包含文件类对象
        
        支持的文件类型：
        - bytes: 字节数据
        - 具有 read 属性的对象（文件句柄）
        - tuple: (filename, content) 或 (filename, content, content_type) 格式
        """
        if not data:
            return False
        for value in data.values():
            # 检查是否为字节流
            if isinstance(value, bytes):
                return True
            # 检查是否为文件句柄（具有read属性）
            if hasattr(value, 'read'):
                return True
            # 检查是否为元组格式的文件 (filename, content) 或 (filename, content, content_type)
            if isinstance(value, tuple) and len(value) >= 2:
                return True
        return False

    def _prepare_multipart_data(self, formdata_data: Dict[str, Any]) -> List[Tuple[str, Any]]:
        """
        准备 multipart/form-data 格式的数据
        
        将普通字段和文件字段统一转换为 httpx 可接受的格式
        
        httpx 的 files 参数支持两种格式：
        1. Dict[str, tuple] - 每个字段只有一个值
        2. List[Tuple[str, tuple]] - 支持同名多值参数（如 status[]）
        
        为了支持数组参数，我们使用列表格式
        """
        prepared_data = []
        
        for key, value in formdata_data.items():
            if value is None:
                continue
            
            # 处理数组类型的值
            if isinstance(value, list):
                # 数组参数：为每个元素创建一个同名字段
                for item in value:
                    if item is None:
                        # 空值也需要发送
                        prepared_data.append((key, (None, "")))
                    elif isinstance(item, tuple):
                        prepared_data.append((key, item))
                    elif isinstance(item, bytes):
                        prepared_data.append((key, (None, item, 'application/octet-stream')))
                    elif hasattr(item, 'read'):
                        prepared_data.append((key, item))
                    else:
                        prepared_data.append((key, (None, str(item) if not isinstance(item, str) else item)))
            # 如果已经是元组格式（文件），直接使用
            elif isinstance(value, tuple):
                prepared_data.append((key, value))
            # 如果是字节数据，包装为文件格式
            elif isinstance(value, bytes):
                prepared_data.append((key, (None, value, 'application/octet-stream')))
            # 如果是文件句柄，直接使用
            elif hasattr(value, 'read'):
                prepared_data.append((key, value))
            # 普通字段，转换为 (None, value) 格式
            else:
                prepared_data.append((key, (None, str(value) if not isinstance(value, str) else value)))
        
        return prepared_data

    def _diagnose_content_type_issue(
        self,
        status_code: int,
        response_text: str,
        headers: Dict[str, str],
        json_data: Optional[Dict[str, Any]],
        form_data: Optional[Dict[str, Any]],
        formdata_data: Optional[Dict[str, Any]],
    ) -> None:
        """
        诊断 Content-Type 相关问题
        
        当请求失败时，检查是否可能是 Content-Type 不匹配导致的问题，
        并给出相应的诊断建议。
        
        Args:
            status_code: HTTP 状态码
            response_text: 响应内容
            headers: 请求头
            json_data: JSON 请求体数据
            form_data: 表单数据
            formdata_data: multipart 表单数据
        """
        # 常见的 Content-Type 相关错误状态码
        content_type_error_codes = [400, 415, 422]
        
        if status_code not in content_type_error_codes:
            return
        
        # 获取当前设置的 Content-Type
        current_content_type = headers.get("content-type", "").lower()
        
        # 检查响应中是否包含 Content-Type 相关的错误信息
        response_lower = response_text.lower() if response_text else ""
        content_type_keywords = [
            "content-type", "content type", "media type", 
            "unsupported media", "invalid content", "expected json",
            "expected form", "multipart", "boundary"
        ]
        
        has_content_type_error = any(kw in response_lower for kw in content_type_keywords)
        
        if has_content_type_error or status_code == 415:
            logger.warning("=" * 60)
            logger.warning("⚠️ 可能的 Content-Type 问题诊断:")
            logger.warning(f"  当前 Content-Type: {current_content_type or '未设置'}")
            
            # 分析数据类型和建议
            if json_data is not None:
                logger.warning("  数据类型: JSON")
                if "application/json" not in current_content_type:
                    logger.warning("  💡 建议: 请求体是 JSON 格式，但 Content-Type 可能不正确")
                    logger.warning("     应该使用: application/json")
            
            elif form_data is not None:
                logger.warning("  数据类型: Form (application/x-www-form-urlencoded)")
                if "application/x-www-form-urlencoded" not in current_content_type:
                    logger.warning("  💡 建议: 请求体是表单格式，但 Content-Type 可能不正确")
                    logger.warning("     应该使用: application/x-www-form-urlencoded")
            
            elif formdata_data is not None:
                logger.warning("  数据类型: FormData (multipart/form-data)")
                if "multipart/form-data" not in current_content_type:
                    logger.warning("  💡 建议: 请求体是 multipart 格式")
                    logger.warning("     Content-Type 应由 httpx 自动设置（包含 boundary）")
                    logger.warning("     如果手动设置了 Content-Type，请移除它")
            
            else:
                logger.warning("  数据类型: 无请求体")
                if current_content_type:
                    logger.warning("  💡 建议: 没有请求体但设置了 Content-Type，可能导致问题")
            
            # 检查常见的配置错误
            if "boundary" in response_lower and formdata_data is not None:
                logger.warning("  ⚠️ 检测到 boundary 相关错误:")
                logger.warning("     multipart/form-data 需要 boundary 参数")
                logger.warning("     请确保不要手动设置 Content-Type，让 httpx 自动处理")
            
            logger.warning("=" * 60)

    async def _send_request(
        self,
        method: str,
        url: str,
        headers: Dict[str, str],
        query_params: Dict[str, Any],
        json_data: Optional[Dict[str, Any]],
        form_data: Optional[Dict[str, Any]],
        formdata_data: Optional[Dict[str, Any]],
    ) -> Dict[str, Any]:
        """发送HTTP请求"""
        async with httpx.AsyncClient(
            verify=self.verify, timeout=self.timeout
        ) as client:
            try:
                # 准备请求参数
                request_kwargs = {
                    "params": query_params,
                    "headers": headers,
                }

                # 为有请求体的方法添加数据
                # 优先级: json > formdata > form
                if method.upper() in ["POST", "PUT", "PATCH", "DELETE"]:
                    if json_data is not None:
                        request_kwargs["json"] = json_data
                    elif formdata_data is not None:
                        # multipart/form-data 类型处理
                        # 使用统一的方法准备数据
                        prepared_data = self._prepare_multipart_data(formdata_data)
                        if prepared_data:
                            request_kwargs["files"] = prepared_data
                            # 移除手动设置的 content-type，让 httpx 自动添加带 boundary 的
                            headers.pop("content-type", None)
                    elif form_data is not None:
                        # application/x-www-form-urlencoded 类型
                        request_kwargs["data"] = form_data

                # 根据HTTP方法发送请求
                request_func = getattr(client, method.lower(), None)
                if request_func is None:
                    raise ValueError(f"不支持的HTTP方法: {method}")

                response = await request_func(url, **request_kwargs)

                # 检查响应状态
                response.raise_for_status()

                # 解析响应
                return self._parse_response(response)

            except httpx.RequestError as e:
                logger.error(f"请求错误: {str(e)}")
                raise ApiError(f"请求发送失败: {str(e)}")
            except httpx.HTTPStatusError as e:
                # 记录详细的HTTP错误信息
                logger.error(f"HTTP状态错误: {e.response.status_code} - {str(e)}")
                logger.error(f"请求URL: {e.request.url}")
                logger.error(f"请求方法: {e.request.method}")

                # 记录响应内容（用于调试）
                response_text = e.response.text
                if response_text:
                    logger.error(f"响应内容: {response_text[:500]}{'...' if len(response_text) > 500 else ''}")

                # 记录响应头（可能包含有用的错误信息）
                if e.response.headers:
                    logger.info(f"响应头: {dict(e.response.headers)}")

                # Content-Type 不匹配诊断
                self._diagnose_content_type_issue(
                    e.response.status_code,
                    response_text,
                    headers,
                    json_data,
                    form_data,
                    formdata_data
                )

                return {
                    "status": "error",
                    "status_code": e.response.status_code,
                    "error": str(e),
                    "response": e.response.text,
                }
            except Exception as e:
                logger.error(f"未知错误: {str(e)}")
                raise ApiError(f"请求处理失败: {str(e)}")

    def _parse_response(self, response: httpx.Response) -> Dict[str, Any]:
        """解析HTTP响应"""
        # 记录响应信息
        logger.info(f"HTTP响应: {response.status_code} {response.reason_phrase}")

        content_type = response.headers.get("content-type", "")
        logger.info(f"响应类型: {content_type}")

        # 记录响应大小
        content_length = len(response.content) if response.content else 0
        logger.info(f"响应大小: {content_length} bytes")

        if content_type.startswith("application/json"):
            try:
                json_response = response.json()
                # 记录JSON响应的基本信息（避免记录过大的数据）
                if isinstance(json_response, dict):
                    logger.info(f"JSON响应键: {list(json_response.keys())}")
                return json_response
            except Exception as e:
                logger.error(f"JSON解析失败: {str(e)}")
                return {
                    "status": "error",
                    "error": f"JSON解析失败: {str(e)}",
                    "raw_response": response.text,
                    "status_code": response.status_code,
                }
        else:
            # 对于非JSON响应，尝试解析为JSON（某些API返回text/plain但内容是JSON）
            if not response.text:
                return {
                    "status": "success",
                    "data": "",
                    "status_code": response.status_code,
                }

            response_preview = response.text[:100] + "..." if len(response.text) > 100 else response.text
            logger.info(f"文本响应预览: {response_preview}")

            # 尝试解析为JSON
            text = response.text.strip()
            if text and (text.startswith('{') or text.startswith('[')):
                try:
                    json_response = json.loads(text)
                    logger.info("文本响应成功解析为JSON")
                    return json_response
                except (json.JSONDecodeError, ValueError) as e:
                    logger.debug(f"文本响应JSON解析失败: {e}")

            # 返回原始文本
            return {
                "status": "success",
                "data": response.text,
                "status_code": response.status_code,
            }


# 兼容性函数 - 保持向后兼容
async def call_api(
    api_config: Dict[str, Any],
    request_data: Optional[Dict[str, Any]] = None,
    need_auth: bool = True,
    timeout: int = 30,
    verify: bool = True,
    save_responses: bool = True,
    save_dir: str = "lzwcai_mcp_dyntoolapi_log_call_api",
) -> Dict[str, Any]:
    """
    通用API调用方法（兼容性函数）

    Args:
        api_config: API配置信息
        request_data: 请求数据
        need_auth: 是否需要认证
        timeout: 请求超时时间（秒）
        verify: 是否验证SSL证书
        save_responses: 是否保存响应到本地JSON文件
        save_dir: 响应保存目录

    Returns:
        API响应结果
    """
    client = ApiClient(timeout=timeout, verify=verify, save_responses=save_responses, save_dir=save_dir)
    return await client.call_api(api_config, request_data, need_auth)


def get_env_user_id() -> Tuple[bool, Optional[str]]:
    """获取环境变量用户ID（兼容性函数）"""
    return UserManager.get_user_id_from_env()


def extract_user_id(
    request_data: Dict[str, Any], is_grouped_format: bool
) -> Optional[str]:
    """提取用户ID（兼容性函数）"""
    return UserManager.extract_user_id_from_request(request_data, is_grouped_format)


def process_auth_headers(
    headers: dict,
    request_data: dict,
    auth_token: dict = None,
) -> dict:
    """处理认证头（兼容性函数）"""
    return HeaderProcessor.process_auth_headers(headers, request_data, auth_token)


def load_generator_api_config(file_path: str = "generator_api.json") -> Dict[str, Any]:
    """加载API配置（兼容性函数）"""
    return ConfigManager.load_api_config(file_path)


async def main():
    """主函数 - 测试示例"""
    request_data = {
        "header": {},
        "body": {"username": "wangpeng1", "password": "Wp147258"},
        "lzwcaiConfig": {"userId": "test_user_123"},
    }

    try:
        config_path = "src/lzwcai_demp_tool_server_business_to_mcp/mcp_generator/src/user_params.json"
        api_config = ConfigManager.load_api_config(config_path)
        logger.info(f"正在尝试连接: {api_config.get('domainUrl')}{api_config.get('apiUrl')}")
        client = ApiClient()
        result = await client.call_api(api_config, request_data)
        logger.info(f"请求结果: {result}")

    except Exception as e:
        logger.error(f"发生错误: {e}")


if __name__ == "__main__":
    asyncio.run(main())
