"""
类实例创建工具

此模块提供了通过字典配置创建类实例的功能，支持嵌套实例的递归创建。
类似于Hydra和Weights & Biases的配置系统。
"""

import importlib
import traceback
from typing import Any, Dict, TypeVar
from unilabos.utils import import_manager, logger

T = TypeVar("T")

# 定义实例创建规范的关键字
INSTANCE_TYPE_KEY = "_cls"  # 类的完整路径
INSTANCE_PARAMS_KEY = "_params"  # 构造函数参数
INSTANCE_ARGS_KEY = "_args"  # 位置参数列表（可选）


def is_instance_config(config: Any) -> bool:
    """
    检查配置是否符合实例创建规范

    Args:
        config: 要检查的配置对象

    Returns:
        是否符合实例创建规范
    """
    if not isinstance(config, dict):
        return False

    return INSTANCE_TYPE_KEY in config and INSTANCE_PARAMS_KEY in config


def import_class(class_path: str) -> type:
    """
    根据类路径导入类

    Args:
        class_path: 类的完整路径，如"pylabrobot.liquid_handling:LiquidHandler"

    Returns:
        导入的类

    Raises:
        ImportError: 如果导入失败
        AttributeError: 如果找不到指定的类
    """
    try:
        return import_manager.get_class(class_path)
    except ValueError as e:
        raise ImportError(f"无法导入类 {class_path}: {str(e)}")
    except (ImportError, AttributeError) as e:
        raise ImportError(f"无法导入类 {class_path}: {str(e)}")


def create_instance_from_config(config: Dict[str, Any]) -> Any:
    """
    从配置字典创建实例，递归处理嵌套的实例配置

    Args:
        config: 配置字典，必须包含_type和_params键

    Returns:
        创建的实例

    Raises:
        ValueError: 如果配置不符合规范
        ImportError: 如果类导入失败
    """
    if not is_instance_config(config):
        raise ValueError(f"配置不符合实例创建规范: {config}")

    class_path = config[INSTANCE_TYPE_KEY]
    params = config[INSTANCE_PARAMS_KEY]
    args = config.get(INSTANCE_ARGS_KEY, [])

    # 递归处理嵌套的实例配置
    processed_args = []
    for arg in args:
        if is_instance_config(arg):
            processed_args.append(create_instance_from_config(arg))
        else:
            processed_args.append(arg)

    processed_params = {}
    for key, value in params.items():
        if is_instance_config(value):
            processed_params[key] = create_instance_from_config(value)
        elif isinstance(value, list):
            # 处理列表中的实例配置
            processed_list = []
            for item in value:
                if is_instance_config(item):
                    processed_list.append(create_instance_from_config(item))
                else:
                    processed_list.append(item)
            processed_params[key] = processed_list
        elif isinstance(value, dict) and not is_instance_config(value):
            # 处理普通字典中可能包含的实例配置
            processed_dict = {}
            for k, v in value.items():
                if is_instance_config(v):
                    processed_dict[k] = create_instance_from_config(v)
                else:
                    processed_dict[k] = v
            processed_params[key] = processed_dict
        else:
            processed_params[key] = value

    # 导入类并创建实例
    cls = import_class(class_path)
    return cls(*processed_args, **processed_params)


def create_config_from_instance(instance: Any, include_args: bool = False) -> Dict[str, Any]:
    """
    从实例创建配置字典（序列化）

    Args:
        instance: 要序列化的实例
        include_args: 是否包含位置参数（通常无法获取）

    Returns:
        配置字典
    """
    if instance is None:
        return {}

    # 获取实例的类路径
    cls = instance.__class__
    class_path = f"{cls.__module__}.{cls.__name__}"

    # 无法获取实例的构造参数，这里返回空字典
    # 实际使用时可能需要手动指定或通过其他方式获取
    return {INSTANCE_TYPE_KEY: class_path, INSTANCE_PARAMS_KEY: {}, INSTANCE_ARGS_KEY: [] if include_args else None}
