import typing
from pathlib import Path
import inspect
from types import NoneType, UnionType
from typing import get_args, get_origin

# ================================================================
# Tool Interface
# ================================================================


def _map_py_to_json_type(py_type: type) -> dict:
    """
    将 Python 类型注解映射到 JSON Schema 类型字典。
    (这个函数与我们之前的版本完全相同)
    """
    # 处理 Optional[T] 或 T | None
    origin = get_origin(py_type)
    if origin in (typing.Union, UnionType):
        args = get_args(py_type)
        non_none_args = [arg for arg in args if arg is not NoneType]
        if len(non_none_args) == 1:
            return _map_py_to_json_type(non_none_args[0])
        else:
            if non_none_args:
                return _map_py_to_json_type(non_none_args[0])
            else:
                return {
                    'type': 'string',
                    'description': 'Union type (defaulted to string)',
                }

    # 处理 Literal["a", "b"]
    if origin == typing.Literal:
        enums = get_args(py_type)
        enum_type = 'string'
        if enums and isinstance(enums[0], int):
            enum_type = 'integer'
        elif enums and isinstance(enums[0], float):
            enum_type = 'number'
        return {'type': enum_type, 'enum': list(enums)}

    # 处理 List[T] 或 list[T]
    if py_type == list or origin == list:
        args = get_args(py_type)
        if args:
            item_schema = _map_py_to_json_type(args[0])
            return {'type': 'array', 'items': item_schema}
        return {'type': 'array'}

    # 处理 Dict[K, V] 或 dict[K, V]
    if py_type == dict or origin == dict:
        return {'type': 'object'}

    # --- 处理基础类型 ---
    if py_type == str:
        return {'type': 'string'}
    if py_type == int:
        return {'type': 'integer'}
    if py_type == float:
        return {'type': 'number'}
    if py_type == bool:
        return {'type': 'boolean'}

    # --- 回退机制 ---
    if py_type == inspect.Parameter.empty or py_type == typing.Any:
        return {
            'type': 'string',
            'description': '(Type not specified, defaulted to string)',
        }

    return {
        'type': 'string',
        'description': f'(Unsupported type: {str(py_type)}, defaulted to string)',
    }


def generate_schema_from_function(func: typing.Callable) -> dict | None:
    """
    从一个函数对象（在运行时）生成 OpenAI Tool Schema。
    """
    from docstring_parser import parse  # pyright: ignore[reportMissingImports]

    # 1. 获取函数签名
    try:
        sig = inspect.signature(func)
    except (ValueError, TypeError):
        return None  # 无法处理的函数（例如某些内置函数）

    # 2. 解析文档字符串
    docstring = inspect.getdoc(func) or ''
    parsed_docstring = parse(docstring)

    func_description = parsed_docstring.short_description or ''
    if parsed_docstring.long_description:
        func_description += '\n' + parsed_docstring.long_description.strip()

    # 提取返回值信息用于 declaredReturnType
    # declared_data_type = None
    # if parsed_docstring.returns:
    #     return_type = parsed_docstring.returns.type_name
    #     return_desc = parsed_docstring.returns.description
    #     if return_type:
    #         declared_data_type = {'type': return_type.strip()}
    #         if return_desc and return_desc.strip():
    #             declared_data_type['note'] = return_desc.strip()

    # 添加返回值说明到函数描述中
    # if parsed_docstring.returns:
    #     return_type = parsed_docstring.returns.type_name or 'Unknown'
    #     return_desc = parsed_docstring.returns.description.strip() if parsed_docstring.returns.description else ''
    #     if return_desc:
    #         func_description += f'\n\nReturns:\n{return_type}: {return_desc}'

    param_descriptions = {
        param.arg_name: param.description for param in parsed_docstring.params
    }

    # 3. 遍历参数并构建 Schema
    schema_properties = {}
    required_params = []

    for name, param in sig.parameters.items():
        if name in ('self', 'cls'):
            continue

        is_required = param.default == inspect.Parameter.empty
        py_type = param.annotation

        origin = get_origin(py_type)
        if origin in (typing.Union, UnionType) and NoneType in get_args(py_type):
            is_required = False

        if is_required:
            required_params.append(name)

        param_schema = _map_py_to_json_type(py_type)
        param_schema['description'] = param_descriptions.get(name, '')

        if param.default != inspect.Parameter.empty:
            param_schema['default'] = param.default

        schema_properties[name] = param_schema

    # 4. 构建最终的 Tool Schema
    parameters_schema = {'type': 'object', 'properties': schema_properties}
    if required_params:
        parameters_schema['required'] = required_params

    tool_schema = {
        'type': 'function',
        'function': {
            'name': func.__name__,
            'description': func_description.strip(),
            'parameters': parameters_schema,
        },
    }

    # 添加 declaredReturnType（如果从 docstring 解析出来了）
    # if declared_data_type:
    #     tool_schema['declaredReturnType'] = declared_data_type

    # 5. 提取权限配置属性（如果存在）
    permission_config = {}

    # 检查函数是否设置了权限属性
    if hasattr(func, 'permissionLevel'):
        permission_config['permissionLevel'] = func.permissionLevel

    if hasattr(func, 'requireExecutionApproval'):
        permission_config['requireExecutionApproval'] = func.requireExecutionApproval

    if hasattr(func, 'requireResultApproval'):
        permission_config['requireResultApproval'] = func.requireResultApproval

    # 将权限配置添加到 tool_schema
    if permission_config:
        tool_schema.update(permission_config)

    return tool_schema
