"""
API基础模块 - 核心API管理和调用功能

这个模块是整个系统的核心，提供了API配置管理、Schema生成、接口调用等基础功能。
主要包含以下组件：

1. ApiBase类: API管理的抽象基类
2. 工具函数: 拼音转换、Schema处理等
3. 常量定义: 认证级别、参数类型等

主要功能:
- API配置的加载和处理
- JSON Schema的生成和验证
- 中文接口名称转拼音命名
- API接口的统一调用管理
- 认证和参数处理

作者: lzwcai
版本: 1.0.0
"""

import json
import re
import pypinyin
from abc import ABC, abstractmethod
from typing import Dict, List, Any, Tuple, Optional, Union

# 导入业务工具模块
from ..business.business_util import (
    generate_json_schema,           # JSON Schema生成
    generate_schema_prompt,         # Schema提示文本生成
    remove_property_from_api_array, # API数组属性移除
)


# ==================== 常量定义 ====================

class AuthenticationLevel:
    """
    API认证级别常量

    定义API接口的认证要求级别：
    - REQUIRED: 需要认证（值为1）
    - NOT_REQUIRED: 不需要认证（值为0）
    """
    REQUIRED = 1        # 需要认证
    NOT_REQUIRED = 0    # 不需要认证


# 导入统一日志配置
from ..util.logger_config import get_logger

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


# ==================== 工具函数 ====================

def pinyin_to_camel(text: str) -> str:
    """
    中文文本转拼音驼峰命名函数

    将中文文本转换为带'tool_'前缀的驼峰命名格式，用于生成API工具的标识符。
    这个函数是系统中重要的命名转换工具，确保中文API名称能够转换为合法的标识符。

    转换规则:
    1. 将所有非字母数字字符（包括标点符号）替换为下划线
    2. 将空格替换为下划线
    3. 移除连续的下划线并去除首尾下划线
    4. 使用pypinyin库将中文转换为拼音
    5. 每个拼音单词首字母大写（驼峰格式）
    6. 添加'tool_'前缀以符合工具命名规范

    参数:
        text: 要转换的中文文本

    返回:
        str: 转换后的驼峰命名字符串，格式为'tool_XxxYyy'

    示例:
        >>> pinyin_to_camel("用户登录")
        'tool_YongHuDengLu'
        >>> pinyin_to_camel("获取订单列表")
        'tool_HuoQuDingDanLieBiao'

    异常处理:
        TypeError: 如果输入不是字符串类型
        ValueError: 如果输入为空字符串

    容错机制:
        - 转换失败时使用hash值生成备用名称
        - 确保始终返回有效的标识符
    """
    # 参数类型检查
    if not isinstance(text, str):
        raise TypeError("text must be a string")

    # 参数内容检查
    if not text.strip():
        raise ValueError("text cannot be empty")

    try:
        logger.debug(f"转换中文文本为拼音: {text}")

        # 第一步：将所有非中文、非字母、非数字的字符（包括中文标点符号）替换为空格
        # 这样可以正确处理中文标点符号（包括中文括号、顿号等）
        # \u4e00-\u9fff 匹配所有中文字符
        # a-zA-Z0-9 匹配英文字母和数字
        cleaned = re.sub(r'[^\u4e00-\u9fffa-zA-Z0-9\s]', ' ', text)
        
        # 第二步：将多个空格合并为一个空格，并去除首尾空格
        cleaned = re.sub(r'\s+', ' ', cleaned).strip()
        
        # 第三步：使用pypinyin库转换为拼音列表
        # pypinyin会将中文转为拼音，英文和数字保持原样
        pinyin_list = pypinyin.lazy_pinyin(cleaned)

        # 第四步：将拼音列表转换为驼峰格式
        # 过滤掉空白字符、下划线等特殊字符，只保留有效的拼音单词
        # 注意：pypinyin对于空格会产生空字符串，需要过滤掉
        camel_case = "".join(
            word.strip().capitalize() 
            for word in pinyin_list 
            if word.strip() and word.strip() not in ['_', '-', '.', ' ']
        )

        # 第五步：添加工具前缀
        result = f"tool_{camel_case}"

        logger.debug(f"拼音转换结果: {text} -> {result}")
        return result

    except Exception as e:
        logger.error(f"拼音转换失败，文本: '{text}', 错误: {str(e)}")

        # 容错处理：生成基于hash的备用名称
        # 使用hash确保相同输入产生相同输出
        fallback = f"tool_Unknown_{hash(text) % 10000}"
        logger.warning(f"使用备用名称: {fallback}")
        return fallback


def _process_api_schema(param: Dict[str, Any]) -> Tuple[Dict[str, Any], str]:
    """
    API参数Schema处理函数

    这个函数负责处理单个API配置，生成对应的JSON Schema和接口名称。
    它是API配置转换的核心函数，将业务平台的API配置转换为MCP工具所需的格式。

    处理流程:
    1. 提取API参数列表
    2. 生成JSON Schema（包含参数类型、描述、默认值等）
    3. 将中文接口名转换为拼音格式的工具名称
    4. 返回处理后的Schema和接口名称

    参数:
        param: API参数配置字典，包含以下字段：
            - interfaceName: 接口名称（中文）
            - parameters: 参数列表
            - 其他API配置信息

    返回:
        tuple: (处理后的JSON Schema, 转换后的接口名称)
            - processed_schema: 符合JSON Schema规范的参数定义
            - interface_name: 转换后的拼音格式接口名称

    异常处理:
        ImportError: 当无法导入必需模块时抛出
        Exception: 当Schema生成失败时抛出

    注意事项:
        - userId参数的处理在请求时进行，而不是在Schema生成时
        - userId现在存储在lzwcaiConfig分组中，支持动态userId值，提高系统灵活性
        - 使用延迟导入避免循环依赖问题
    """
    try:
        # 延迟导入避免循环依赖
        # 这些模块可能会反过来导入当前模块
        from .core_server import get_env_user_id
        # from ..business.business_util import remove_property_from_api_item

        logger.debug(f"处理API参数: {param.get('interfaceName', 'N/A')}")

        # 提取API参数列表并生成JSON Schema
        parameters = param.get("parameters", [])
        logger.debug(f"参数数量: {len(parameters)}")

        # 调用业务工具模块生成标准JSON Schema
        schema = generate_json_schema(parameters)

        # 重要说明：userId参数的处理策略
        # 为了支持动态userId值，userId参数的处理在请求时进行，
        # 而不是在Schema生成时进行。这样可以支持不同用户的动态切换。
        # userId现在存储在lzwcaiConfig分组中。
        logger.debug("Schema生成完成，userId处理将在请求时进行")

        # 生成接口名称（中文转拼音）
        interface_name_raw = param.get("interfaceName", "")
        if interface_name_raw:
            # 使用拼音转换函数生成工具名称
            interface_name = pinyin_to_camel(interface_name_raw)
        else:
            # 备用名称，防止接口名称为空
            interface_name = "tool_Unknown"

        logger.debug(f"生成接口名称: {interface_name_raw} -> {interface_name}")
        return schema, interface_name

    except ImportError as e:
        logger.error(f"导入必需模块失败: {str(e)}")
        raise
    except Exception as e:
        logger.error(f"处理API Schema时出错: {str(e)}")
        raise


def get_api_configs_map(api_configs: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
    """
    API配置映射处理函数

    这个函数是API配置处理的核心，负责将原始的API配置列表转换为
    包含Schema和描述信息的处理后配置列表。每个API配置都会被转换为
    一个完整的MCP工具定义。

    处理内容:
    1. 为每个API生成JSON Schema
    2. 转换中文接口名为拼音格式
    3. 生成工具描述（业务描述 + 参数说明）
    4. 创建完整的工具配置对象
    5. 错误处理和容错机制

    参数:
        api_configs: API配置字典列表，每个字典包含：
            - interfaceName: 接口名称
            - businessPrompts: 业务描述
            - parameters: 参数列表
            - 其他API配置信息

    返回:
        list: 处理后的API配置列表，每个配置包含：
            - interfaceName: 转换后的接口名称（拼音格式）
            - schema: JSON Schema对象
            - schema_description: 完整的工具描述
            - 原始配置的所有其他字段

    异常处理:
        TypeError: 如果api_configs不是列表类型
        ValueError: 如果api_configs为空列表

    容错机制:
        - 跳过无效的配置项（非字典类型）
        - 处理失败时保留原始配置并添加错误标记
        - 详细记录处理过程和错误信息
    """
    # 参数验证
    if not isinstance(api_configs, list):
        raise TypeError("api_configs must be a list")

    if not api_configs:
        raise ValueError("api_configs cannot be empty")

    logger.info(f"开始处理 {len(api_configs)} 个API配置")
    api_array = []

    # 遍历处理每个API配置
    for i, param in enumerate(api_configs):
        # 检查配置项类型
        if not isinstance(param, dict):
            logger.warning(
                f"跳过无效的API配置 (索引 {i}): 不是字典类型"
            )
            continue

        try:
            logger.debug(f"处理API配置 {i}: {param.get('interfaceName', 'N/A')}")

            # 处理Schema和接口名称
            schema, interface_name = _process_api_schema(param)

            # 获取业务描述
            description = param.get("businessPrompts", "")

            # 生成参数Schema的提示文本
            schema_prompt = generate_schema_prompt(schema)

            # 组合工具描述：业务描述 + 参数说明
            if description:
                schema_description = f"{description}\n\n{schema_prompt}"
            else:
                schema_description = f"工具描述: 暂无描述\n\n{schema_prompt}"

            # 创建处理后的API配置对象
            processed_config = {
                **param,                                    # 保留原始配置的所有字段
                "interfaceName": interface_name,            # 更新接口名称为拼音格式
                "schema": schema,                           # 添加JSON Schema
                "schema_description": schema_description,   # 添加完整描述
            }

            api_array.append(processed_config)
            logger.debug(f"API配置 {i} 处理完成: {interface_name}")

        except Exception as e:
            # 处理异常：记录错误但不中断整个处理流程
            logger.error(f"处理API配置 {i} 时出错: {str(e)}")
            logger.debug(f"错误的API配置内容: {param}")

            # 创建错误配置对象，保留原始数据但添加错误标记
            error_config = {
                **param,                                        # 保留原始配置
                "interfaceName": f"tool_Error_{i}",            # 错误标记的接口名
                "schema": {},                                   # 空Schema
                "schema_description": f"配置处理错误: {str(e)}", # 错误描述
            }
            api_array.append(error_config)

    logger.info(f"API配置处理完成，成功处理 {len(api_array)} 个配置")
    return api_array


# ==================== API基础管理类 ====================

class ApiBase(ABC):
    """
    API管理抽象基类

    这个类是整个API管理系统的核心基类，提供了API配置处理、
    Schema生成、接口调用等基础功能。所有具体的API管理实现
    都应该继承这个类。

    主要职责:
    1. API配置的加载和验证
    2. API配置到工具定义的转换
    3. 提供统一的API调用接口
    4. 管理API配置的生命周期
    5. 提供配置查询和检索功能

    设计模式:
        - 抽象基类模式：定义API管理的标准接口
        - 模板方法模式：提供通用的处理流程
        - 策略模式：支持不同的认证和调用策略

    属性:
        api_configs: 原始API配置列表
        api_configs_map: 处理后的API配置映射表
    """

    def __init__(self, api_configs: List[Dict[str, Any]]) -> None:
        """
        初始化API基础管理器

        这个构造函数负责初始化API管理器，处理传入的API配置列表，
        并生成相应的工具定义映射表。

        初始化流程:
        1. 验证输入参数的类型和内容
        2. 保存原始API配置
        3. 调用配置映射函数生成工具定义
        4. 记录初始化结果
        5. 可选的调试输出

        参数:
            api_configs: API配置字典列表，每个字典包含完整的API定义

        异常处理:
            TypeError: 如果api_configs不是列表类型
            ValueError: 如果api_configs为空列表

        注意事项:
            - 配置验证在映射函数中进行
            - 支持部分配置失败的容错处理
            - 调试模式下可以输出Schema到文件
        """
        # 参数类型验证
        if not isinstance(api_configs, list):
            raise TypeError("api_configs must be a list")

        # 参数内容验证
        if not api_configs:
            raise ValueError("api_configs cannot be empty")

        # 保存原始配置
        self.api_configs = api_configs

        # 生成处理后的配置映射表
        # 这是核心处理步骤，将原始配置转换为MCP工具定义
        self.api_configs_map = get_api_configs_map(api_configs)

        logger.info(f"ApiBase初始化完成，共处理 {len(self.api_configs)} 个API配置")

        # 可选的调试输出（默认关闭）
        # 在开发和调试阶段可以启用这个功能
        # self._save_debug_schema()

    def _save_debug_schema(self) -> None:
        """
        保存调试Schema到文件

        这个方法用于开发和调试阶段，将处理后的API配置映射表
        保存到JSON文件中，方便查看和分析Schema生成结果。

        输出文件:
            output_schema.json: 包含所有处理后的API配置

        特性:
            - UTF-8编码确保中文正确显示
            - 格式化输出便于阅读
            - 异常安全，不会影响主要功能
        """
        try:
            with open("output_schema.json", "w", encoding="utf-8") as f:
                json.dump(self.api_configs_map, f, ensure_ascii=False, indent=4)
            logger.debug("调试Schema已保存到 output_schema.json")
        except Exception as e:
            logger.error(f"保存调试Schema失败: {str(e)}")

    async def call_interface(
        self, api_config: Dict[str, Any], request_data: Dict[str, Any]
    ) -> Any:
        """
        API接口调用方法

        这是ApiBase类的核心方法，负责调用具体的API接口。
        它处理认证逻辑、参数传递和错误处理，为上层提供统一的API调用接口。

        调用流程:
        1. 验证输入参数的类型
        2. 导入核心服务器模块（避免循环依赖）
        3. 判断是否需要认证
        4. 调用底层API接口
        5. 返回API响应结果

        认证处理:
            - 根据API配置中的authenticationRequired字段判断是否需要认证
            - 支持两种认证级别：REQUIRED(1) 和 NOT_REQUIRED(0)
            - 认证逻辑由core_server模块的call_api函数处理

        参数:
            api_config: API配置字典，包含：
                - authenticationRequired: 认证要求级别
                - apiUrl: API接口地址
                - method: HTTP方法
                - 其他API配置信息
            request_data: 请求数据字典，包含：
                - header: 请求头参数
                - query: 查询参数
                - body: 请求体参数
                - lzwcaiConfig: 配置参数（包含userId）

        返回:
            Any: API接口的响应数据，通常是字典格式

        异常处理:
            TypeError: 如果参数不是字典类型
            ImportError: 如果无法导入核心服务器模块
            Exception: 如果API调用失败

        设计考虑:
            - 使用延迟导入避免循环依赖
            - 统一的错误处理和日志记录
            - 支持异步调用以提高性能
        """
        # 参数类型验证
        if not isinstance(api_config, dict):
            raise TypeError("api_config must be a dictionary")

        if not isinstance(request_data, dict):
            raise TypeError("request_data must be a dictionary")

        try:
            # 延迟导入避免循环依赖
            # core_server模块可能会导入当前模块
            from .core_server import call_api

            # 判断认证要求
            # 从API配置中获取认证要求，默认为不需要认证
            auth_required = api_config.get(
                "authenticationRequired", AuthenticationLevel.NOT_REQUIRED
            )
            need_auth = auth_required == AuthenticationLevel.REQUIRED

            logger.info(f"调用API接口，需要认证: {need_auth}")
            logger.debug(f"API配置: {api_config.get('apiUrl', 'N/A')}")

            # 调用底层API接口
            # call_api函数处理具体的HTTP请求、认证、参数处理等
            return await call_api(api_config, request_data, need_auth=need_auth)

        except ImportError as e:
            logger.error(f"导入call_api函数失败: {str(e)}")
            raise ImportError(
                f"无法导入必需的API调用功能: {str(e)}"
            )
        except Exception as e:
            logger.error(f"API调用失败: {str(e)}")
            logger.debug("API调用异常详情:", exc_info=True)
            raise

    def get_api_config_by_name(self, interface_name: str) -> Optional[Dict[str, Any]]:
        """
        根据接口名称获取API配置

        这个方法用于根据接口名称查找对应的API配置。
        接口名称是经过拼音转换后的工具名称（如：tool_YongHuDengLu）。

        查找逻辑:
            - 遍历所有处理后的API配置
            - 匹配interfaceName字段
            - 返回第一个匹配的配置

        参数:
            interface_name: 要查找的接口名称（拼音格式）

        返回:
            Optional[Dict[str, Any]]: 找到的API配置字典，未找到则返回None

        使用场景:
            - MCP工具调用时查找对应的API配置
            - 验证工具名称是否存在
            - 获取特定工具的配置信息
        """
        # 参数类型检查
        if not isinstance(interface_name, str):
            logger.warning(f"接口名称类型错误: {type(interface_name)}")
            return None

        # 遍历查找匹配的配置
        for config in self.api_configs_map:
            if config.get("interfaceName") == interface_name:
                logger.debug(f"找到接口配置: {interface_name}")
                return config

        logger.debug(f"未找到接口配置: {interface_name}")
        return None

    def get_all_interface_names(self) -> List[str]:
        """
        获取所有可用的接口名称列表

        这个方法返回所有已处理的API配置的接口名称列表。
        主要用于调试、监控和工具列表展示。

        返回:
            List[str]: 所有接口名称的列表（拼音格式）

        特性:
            - 过滤掉空的接口名称
            - 返回的是处理后的拼音格式名称
            - 按配置顺序返回

        使用场景:
            - 系统监控和状态检查
            - 调试和日志记录
            - 管理界面展示可用工具
        """
        interface_names = [
            config.get("interfaceName", "")
            for config in self.api_configs_map
            if config.get("interfaceName")  # 过滤空名称
        ]

        logger.debug(f"获取到 {len(interface_names)} 个接口名称")
        return interface_names

    def get_schema_by_name(self, interface_name: str) -> Optional[Dict[str, Any]]:
        """
        根据接口名称获取JSON Schema

        这个方法是get_api_config_by_name的便捷包装，
        直接返回指定接口的JSON Schema定义。

        参数:
            interface_name: 接口名称（拼音格式）

        返回:
            Optional[Dict[str, Any]]: JSON Schema字典，未找到则返回None

        使用场景:
            - 参数验证
            - 文档生成
            - 客户端工具定义
        """
        config = self.get_api_config_by_name(interface_name)
        if config:
            return config.get("schema")
        return None

    @property
    def config_count(self) -> int:
        """
        获取API配置数量

        这是一个属性方法，返回当前管理的API配置总数。
        主要用于监控、日志记录和状态检查。

        返回:
            int: API配置的数量
        """
        return len(self.api_configs_map)

    def __repr__(self) -> str:
        """
        ApiBase对象的字符串表示

        提供对象的简洁字符串表示，主要用于调试和日志记录。

        返回:
            str: 对象的字符串表示，格式为"ApiBase(configs=数量)"
        """
        return f"ApiBase(configs={self.config_count})"
