"""
MCP创建工具的辅助函数模块

包含文件字段处理、参数预处理等功能
"""

import logging
import re
from urllib.parse import urlparse
import os
from src.utils.logger_config import get_logger

logger = get_logger(__name__)

file_type_details = {
        "document": {
            "extensions": "TXT, MD, MARKDOWN, PDF, HTML, XLSX, XLS, DOCX, CSV, EML, MSG, PPTX, PPT, XML, EPUB",
            "description": "文档文件"
        },
        "image": {
            "extensions": "JPG, JPEG, PNG, GIF, WEBP, SVG",
            "description": "图片文件"
        },
        "audio": {
            "extensions": "MP3, M4A, WAV, WEBM, AMR",
            "description": "音频文件"
        },
        "video": {
            "extensions": "MP4, MOV, MPEG, MPGA",
            "description": "视频文件"
        },
        "custom": {
            "extensions": "",
            "description": "其他文件类型"
        }
    }

def process_file_arguments(arguments, current_tool_file_fields, dify_api, tool_name):
    """
    处理arguments中的文件类型字段

    Args:
        arguments (dict): 工具调用的参数字典
        current_tool_file_fields (list): 当前工具的文件字段信息列表
            数据结构: [{'variable': 'txt', 'label': '输入', 'required': True, 'max_length': 48,
                      'allowed_file_types': ['document'], 'allowed_file_upload_methods': ['local_file', 'remote_url'],
                      'allowed_file_extensions': [], 'is_list': False}]
        dify_api: Dify API实例，包含file_parameter_pretreatment方法
        tool_name (str): 工具名称，用于日志记录

    Returns:
        dict: 处理后的arguments字典

    Raises:
        Exception: 当文件处理过程中发生严重错误时抛出
    """
    if not arguments or not current_tool_file_fields:
        logger.info(f"工具 {tool_name}: 无需处理文件字段 (arguments={bool(arguments)}, file_fields={len(current_tool_file_fields) if current_tool_file_fields else 0})")
        return arguments

    # 创建文件字段变量名到字段信息的映射，用于快速查找
    file_field_map = {field['variable']: field for field in current_tool_file_fields}
    file_field_variables = set(file_field_map.keys())
    logger.info(f"工具 {tool_name} 的文件字段变量名: {file_field_variables}")

    # 创建arguments的副本，避免修改原始数据
    processed_arguments = arguments.copy()

    # 处理arguments中的文件字段
    for arg_name, arg_value in arguments.items():
        # 检查参数名是否是文件字段
        if arg_name in file_field_variables:
            logger.info(f"工具 {tool_name}: 发现文件字段 {arg_name}，值: {arg_value}")

            # 检查参数值是否包含文件信息
            files_to_process = _extract_files_from_argument(arg_value, arg_name, tool_name)

            if not files_to_process:
                logger.info(f"工具 {tool_name}: 字段 {arg_name} 不是文件格式，跳过处理")
                continue

            # 调用文件预处理方法
            try:

                logger.info(f"工具 {tool_name}: 准备处理文件列表: {files_to_process}")

                # 为每个文件对象添加必要的字段
                for file_obj in files_to_process:
                    # 设置传输方式为 remote_url（从URL下载并上传）
                    if 'transfer_method' not in file_obj:
                        file_obj['transfer_method'] = 'remote_url'
                    
                    # 自动识别文件类型
                    if 'type' not in file_obj and 'url' in file_obj:
                        file_obj['type'] = get_file_type_from_url(file_obj['url'])
                        logger.info(f"工具 {tool_name}: 自动识别文件类型为 {file_obj['type']}")

                # 调用文件预处理：下载文件并上传到Dify，获取upload_file_id
                processed_files = dify_api.file_parameter_pretreatment(files_to_process)

                if not processed_files or len(processed_files) == 0:
                    logger.error(f"工具 {tool_name}: 文件预处理失败，未返回有效结果")
                    continue

                # 过滤掉上传失败的文件
                valid_files = [f for f in processed_files if f.get('upload_file_id') and not f.get('upload_error')]
                if not valid_files:
                    logger.error(f"工具 {tool_name}: 所有文件上传失败")
                    continue

                logger.info(f"工具 {tool_name}: 文件预处理完成，成功上传 {len(valid_files)} 个文件")

                # 获取当前字段的配置信息，判断是单文件还是多文件
                field_config = file_field_map.get(arg_name, {})
                is_list = field_config.get('is_list', False)
                
                # 更新processed_arguments中的值
                _update_processed_argument(processed_arguments, arg_name, arg_value, valid_files, tool_name, is_list)

            except Exception as e:
                logger.error(f"工具 {tool_name}: 处理文件字段 {arg_name} 时发生错误: {str(e)}")
                # 继续执行，不中断整个流程
                continue

    return processed_arguments


def _extract_files_from_argument(arg_value, arg_name, tool_name):
    """
    从参数值中提取文件信息

    Args:
        arg_value: 参数值（可以是字符串URL、文件对象或文件列表）
        arg_name (str): 参数名称
        tool_name (str): 工具名称

    Returns:
        list: 文件列表，如果不是文件格式则返回None
    """
    # 情况1: 单个字符串URL
    if isinstance(arg_value, str):
        # 检查是否是有效的URL
        if arg_value.startswith(('http://', 'https://')):
            file_obj = {'url': arg_value}
            logger.info(f"工具 {tool_name}: 将字符串URL转换为文件对象: {file_obj}")
            return [file_obj]
        else:
            logger.warning(f"工具 {tool_name}: 字符串不是有效的URL: {arg_value}")
            return None
    
    # 情况2: 单个文件对象
    if isinstance(arg_value, dict) and _is_file_object(arg_value):
        files_to_process = [arg_value]
        logger.info(f"工具 {tool_name}: 处理单个文件对象: {files_to_process}")
        return files_to_process

    # 情况3: 文件列表
    elif isinstance(arg_value, list) and len(arg_value) > 0:
        # 检查列表中是否包含文件对象或URL字符串
        valid_files = []
        for item in arg_value:
            if isinstance(item, dict) and _is_file_object(item):
                valid_files.append(item)
            elif isinstance(item, str) and item.startswith(('http://', 'https://')):
                valid_files.append({'url': item})
        
        if valid_files:
            logger.info(f"工具 {tool_name}: 处理文件列表: {valid_files}")
            return valid_files

    return None


def _is_file_object(obj):
    """
    判断对象是否是文件对象

    Args:
        obj (dict): 要检查的对象

    Returns:
        bool: 如果是文件对象返回True，否则返回False
    """
    if not isinstance(obj, dict):
        return False

    # 检查是否包含文件对象的关键字段
    file_indicators = ['type', 'transfer_method', 'url', 'upload_file_id', 'file_url', 'file_name']
    return any(key in obj for key in file_indicators)


def _update_processed_argument(processed_arguments, arg_name, original_value, processed_files, tool_name, is_list=False):
    """
    更新处理后的参数值
    
    根据字段类型决定输出格式：
    - file-list (is_list=True): 输出列表格式 []
    - file (is_list=False): 输出对象格式 {}

    Args:
        processed_arguments (dict): 处理后的参数字典
        arg_name (str): 参数名称
        original_value: 原始参数值（可以是字符串URL、文件对象或文件列表）
        processed_files (list): 处理后的文件对象列表
        tool_name (str): 工具名称
        is_list (bool): 是否为多文件类型 (file-list=True, file=False)
    """
    if not processed_files:
        logger.warning(f"工具 {tool_name}: 文件处理后为空，保持原值")
        return
        
    if is_list:
        # file-list 类型：使用完整列表
        processed_arguments[arg_name] = processed_files
        logger.info(f"工具 {tool_name}: 字段 {arg_name} 是 file-list 类型，输出 {len(processed_files)} 个文件")
    else:
        # file 类型：只取第一个文件对象
        processed_arguments[arg_name] = processed_files[0]
        logger.info(f"工具 {tool_name}: 字段 {arg_name} 是 file 类型，输出单个对象")

    logger.info(f"工具 {tool_name}: 字段 {arg_name} 最终值: {processed_arguments[arg_name]}")


def validate_file_field_configuration(file_fields, tool_name):
    """
    验证文件字段配置的有效性

    Args:
        file_fields (list): 文件字段配置列表
        tool_name (str): 工具名称

    Returns:
        bool: 配置是否有效
    """
    if not file_fields:
        return True

    for field in file_fields:
        if not isinstance(field, dict):
            logger.warning(f"工具 {tool_name}: 文件字段配置不是字典格式: {field}")
            return False

        if 'variable' not in field or not field['variable']:
            logger.warning(f"工具 {tool_name}: 文件字段缺少variable字段: {field}")
            return False

    return True


def get_file_field_summary(file_fields, tool_name):
    """
    获取文件字段的摘要信息

    Args:
        file_fields (list): 文件字段配置列表
        tool_name (str): 工具名称

    Returns:
        dict: 文件字段摘要信息
    """
    if not file_fields:
        return {
            'count': 0,
            'variables': [],
            'required_count': 0,
            'optional_count': 0
        }

    variables = [field.get('variable', '') for field in file_fields if field.get('variable')]
    required_count = sum(1 for field in file_fields if field.get('required', False))
    optional_count = len(file_fields) - required_count

    summary = {
        'count': len(file_fields),
        'variables': variables,
        'required_count': required_count,
        'optional_count': optional_count
    }

    logger.info(f"工具 {tool_name} 文件字段摘要: {summary}")
    return summary


def get_file_type_from_url(url):
    """
    根据URL地址返回文件类型

    Args:
        url (str): 文件的URL地址

    Returns:
        str: 文件类型 ('document', 'image', 'audio', 'video', 'custom')

    Examples:
        >>> get_file_type_from_url("http://example.com/file.pdf")
        'document'
        >>> get_file_type_from_url("http://example.com/image.jpg")
        'image'
        >>> get_file_type_from_url("http://example.com/video.mp4")
        'video'
    """
    if not url or not isinstance(url, str):
        logger.warning(f"无效的URL: {url}")
        return 'custom'

    try:
        # 解析URL获取路径
        parsed_url = urlparse(url)
        path = parsed_url.path

        # 从路径中提取文件扩展名
        file_extension = os.path.splitext(path)[1].lower().lstrip('.')

        # 如果没有扩展名，尝试从查询参数中提取
        if not file_extension:
            # 使用正则表达式匹配常见的文件扩展名模式
            extension_pattern = r'\.([a-zA-Z0-9]{2,5})(?:\?|$|&)'
            match = re.search(extension_pattern, url)
            if match:
                file_extension = match.group(1).lower()

        logger.info(f"从URL {url} 提取的文件扩展名: {file_extension}")

        # 根据扩展名判断文件类型
        for file_type, details in file_type_details.items():
            if file_type == 'custom':
                continue

            # 将支持的扩展名转换为小写列表
            supported_extensions = [ext.strip().lower() for ext in details['extensions'].split(',')]

            if file_extension in supported_extensions:
                logger.info(f"URL {url} 匹配文件类型: {file_type}")
                return file_type

        # 如果没有匹配到任何类型，返回custom
        logger.info(f"URL {url} 未匹配到已知文件类型，返回custom")
        return 'custom'

    except Exception as e:
        logger.error(f"解析URL {url} 时发生错误: {str(e)}")
        return 'custom'