import json
from typing import Dict, List, Any, Tuple, Optional
import logging
from pathlib import Path


# 常量定义
DEFAULT_NUMBER_LIMITS = 3  # 默认文件数量限制


def process_user_input_form(
    user_input_form: List[Dict[str, Any]],
) -> Tuple[Dict[str, Any], List[str]]:
    """
    处理Dify用户输入表单，生成对应的JSON Schema properties和required列表

    参数:
        user_input_form: Dify应用的用户输入表单配置

    返回:
        properties: 表单字段的properties字典
        required: 必填字段列表
    """
    properties = {}
    required = []

    if not user_input_form:
        return properties, required

    for param in user_input_form:
        try:
            # 直接获取字典的第一个键,而不是通过list转换
            param_type = next(iter(param))
            param_info = param[param_type]
            property_name = param_info["variable"]

            properties[property_name] = {
                "type": param_type,
                "description": param_info["label"],
            }

            if param_info.get("required", False):
                required.append(property_name)
        except (KeyError, StopIteration) as e:
            logging.warning(f"处理用户输入表单项时出错: {e}, 跳过此项")
            continue

    return properties, required


def process_file_upload(file_upload: Optional[Dict[str, Any]]) -> Dict[str, Any]:
    """
    处理Dify文件上传配置，生成对应的JSON Schema properties

    设计为通用实现，支持任意文件类型配置

    参数:
        file_upload: Dify应用的文件上传配置

    返回:
        file_properties: 文件上传的properties字典
    """
    # 检查是否存在文件上传配置
    if not file_upload:
        return {}

    # 收集所有启用的文件类型信息
    enabled_types = []
    max_items = 0
    supported_transfer_methods = set()
    file_type_configs = {}

    for file_type, config in file_upload.items():
        if not config.get("enabled", False):
            continue

        enabled_types.append(file_type)
        number_limits = config.get("number_limits", DEFAULT_NUMBER_LIMITS)
        max_items += number_limits
        type_transfer_methods = config.get("transfer_methods", [])
        supported_transfer_methods.update(type_transfer_methods)

        # 存储每种文件类型的详细配置
        file_type_configs[file_type] = {
            "number_limits": number_limits,
            "transfer_methods": type_transfer_methods,
        }

    # 如果没有启用的文件类型，返回空字典
    if not enabled_types:
        return {}

    # 构建文件项的JSON Schema
    file_item_schema = _build_file_item_schema(
        enabled_types, supported_transfer_methods, file_type_configs
    )

    # 构建最终的files属性
    file_properties = {
        "files": {
            "type": "array",
            "items": file_item_schema,
            "description": "支持多种文件类型的文件列表",
            "maxItems": max_items,
        }
    }

    return file_properties


def _build_file_item_schema(
    enabled_types: List[str],
    supported_transfer_methods: set,
    file_type_configs: Dict[str, Dict[str, Any]],
) -> Dict[str, Any]:
    """
    构建文件项的JSON Schema

    参数:
        enabled_types: 启用的文件类型列表
        supported_transfer_methods: 支持的传输方式集合
        file_type_configs: 每种文件类型的配置信息

    返回:
        file_item_schema: 文件项的JSON Schema
    """
    file_item_schema = {
        "type": "object",
        "properties": {
            "type": {
                "type": "string",
                "enum": enabled_types,
                "description": "文件类型",
            },
            "transfer_method": {
                "type": "string",
                "enum": list(supported_transfer_methods),
                "description": "传输方式",
            },
        },
    }

    # 添加条件属性
    if "remote_url" in supported_transfer_methods:
        file_item_schema["properties"]["url"] = {
            "type": "string",
            "format": "uri",
            "description": "文件URL (当传输方式为remote_url时使用)",
        }

    if "local_file" in supported_transfer_methods:
        file_item_schema["properties"]["upload_file_id"] = {
            "type": "string",
            "description": "上传文件ID (当传输方式为local_file时使用)",
        }

    # 添加条件验证逻辑
    file_item_schema["allOf"] = []

    # 为每种文件类型添加验证规则
    for file_type, type_config in file_type_configs.items():
        type_methods = type_config["transfer_methods"]

        # 基本验证
        file_item_schema["allOf"].append(
            {
                "if": {"properties": {"type": {"const": file_type}}},
                "then": {
                    "properties": {
                        "transfer_method": {
                            "enum": type_methods,
                            "description": f"{file_type}类型支持的传输方式: {', '.join(type_methods)}",
                        }
                    }
                },
            }
        )

        # 为每种传输方法添加类型特定的验证
        _add_transfer_method_validations(file_item_schema, file_type, type_methods)

    return file_item_schema


def _add_transfer_method_validations(
    file_item_schema: Dict[str, Any], file_type: str, type_methods: List[str]
) -> None:
    """
    为每种传输方法添加类型特定的验证

    参数:
        file_item_schema: 文件项JSON Schema
        file_type: 文件类型
        type_methods: 该类型支持的传输方法列表
    """
    for method in type_methods:
        if method == "remote_url":
            file_item_schema["allOf"].append(
                {
                    "if": {
                        "properties": {
                            "type": {"const": file_type},
                            "transfer_method": {"const": "remote_url"},
                        },
                        "required": ["type", "transfer_method"],
                    },
                    "then": {"required": ["url"]},
                }
            )
        elif method == "local_file":
            file_item_schema["allOf"].append(
                {
                    "if": {
                        "properties": {
                            "type": {"const": file_type},
                            "transfer_method": {"const": "local_file"},
                        },
                        "required": ["type", "transfer_method"],
                    },
                    "then": {"required": ["upload_file_id"]},
                }
            )


def convert_dify_params_to_schema(tool_params: Dict[str, Any]) -> Dict[str, Any]:
    """
    将用户输入表单和文件上传配置组合成新的结构

    参数:
        tool_params: 包含user_input_form和file_upload的参数字典

    返回:
        组合后的结构
    """
    # 参数验证
    if not isinstance(tool_params, dict):
        raise TypeError("tool_params 必须是字典类型")

    # 处理用户输入表单
    properties, required = process_user_input_form(
        tool_params.get("user_input_form", [])
    )

    # 处理文件上传配置
    file_properties = process_file_upload(tool_params.get("file_upload"))

    # 创建新的结构
    result = {
        "inputs": {"type": "object", "properties": properties, "required": required},
        # "userId": {
        #     "oneOf": [{"type": "number"}, {"type": "string"}],
        #     "description": "您的员工ID，用于识别您的员工身份",
        #     "required": True,
        # },
    }

    # 如果有文件上传配置，添加files字段
    if file_properties:
        result["files"] = file_properties.get("files", {})

    return result


def finalize_schema_structure(mock_result: Dict[str, Any]) -> Dict[str, Any]:
    """
    将mock_result构建为符合要求的map_mock_result格式

    参数:
        mock_result: 通过convert_dify_params_to_schema函数获取的结果

    返回:
        构建后的map_mock_result字典
    """
    # 确定required字段
    # required_fields = ["userId"]
    required_fields = []

    # 只有当inputs的required有值时，才添加inputs到顶层required
    if (
        mock_result.get("inputs", {}).get("required")
        and len(mock_result["inputs"]["required"]) > 0
    ):
        required_fields.append("inputs")

    # 如果有文件上传，也可以考虑添加files到required
    if "files" in mock_result:
        # 可以根据需求决定是否将files添加到required
        # required_fields.append("files")
        pass

    return {
        "type": "object",
        "properties": mock_result,
        "required": required_fields,
    }


def create_json_file(data: Dict[str, Any], filename: str = "output.json") -> None:
    """
    将数据保存为JSON文件

    参数:
        data: 要保存的数据
        filename: 保存的文件名
    """
    try:
        # 获取mock数据
        mock_result = convert_dify_params_to_schema(data)

        # 使用封装的方法构建map_mock_result
        map_mock_result = finalize_schema_structure(mock_result)

        # 确保目标目录存在
        output_path = Path(filename)
        output_path.parent.mkdir(parents=True, exist_ok=True)

        # 将结果写入JSON文件
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(map_mock_result, f, ensure_ascii=False, indent=4)

        logging.info(f"已成功将数据保存至 {filename}")
        print(f"已成功将数据保存至 {filename}")

    except Exception as e:
        error_msg = f"保存JSON文件时出错: {e}"
        logging.error(error_msg)
        raise IOError(error_msg)


if __name__ == "__main__":
    # 配置日志
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    )

    # 示例数据
    api_data = {
        "opening_statement": "",
        "suggested_questions": [],
        "suggested_questions_after_answer": {"enabled": False},
        "speech_to_text": {"enabled": False},
        "text_to_speech": {"enabled": False, "language": "", "voice": ""},
        "retriever_resource": {"enabled": False},
        "annotation_reply": {"enabled": False},
        "more_like_this": {"enabled": False},
        "user_input_form": [
            {
                "paragraph": {
                    "label": "文案内容",
                    "max_length": 33024,
                    "options": [],
                    "required": True,
                    "type": "paragraph",
                    "variable": "content",
                }
            }
        ],
        "sensitive_word_avoidance": {"enabled": False},
        "file_upload": {
            "image": {
                "enabled": False,
                "number_limits": 3,
                "transfer_methods": ["local_file", "remote_url"],
            }
        },
        "system_parameters": {"image_file_size_limit": "10"},
    }

    try:
        create_json_file(api_data)
    except Exception as e:
        logging.error(f"程序执行失败: {e}")
