"""
Bean工具模块

提供对象序列化和反序列化功能，支持：
- 字典转对象（Bean）
- 对象列表批量转换
- 对象转字典
- 基础Bean类

Example:
    >>> class User(BaseBean):
    ...     def __init__(self):
    ...         self.name = ""
    ...         self.age = 0
    >>> data = {"name": "Alice", "age": 30}
    >>> user = BeanUtil.parse2bean(data, User)
"""
import json
import logging
from typing import Any, Dict, List, Optional, Type, TypeVar

logger = logging.getLogger(__name__)

# 泛型类型变量
T = TypeVar("T")


class BeanError(Exception):
    """
    Bean操作异常类

    Attributes:
        code: 错误代码
        message: 错误消息
    """

    def __init__(self, code: int = -100, message: str = "BEAN_ERROR"):
        """
        初始化异常

        Args:
            code: 错误代码
            message: 错误消息
        """
        super().__init__(message)
        self.code = code
        self.message = message

    def __str__(self) -> str:
        """
        返回异常的字符串表示

        Returns:
            JSON格式的字符串
        """
        return json.dumps({"code": self.code, "message": self.message})


class BeanUtil:
    """
    Bean工具类

    提供静态方法进行对象和字典之间的转换。

    Example:
        >>> class Person:
        ...     def __init__(self):
        ...         self.name = ""
        >>> data = {"name": "Alice", "extra": "ignored"}
        >>> person = BeanUtil.parse2bean(data, Person)
        >>> print(person.name)  # Alice
    """

    @staticmethod
    def parse2bean(data: Optional[Dict[str, Any]], cls: Type[T]) -> Optional[T]:
        """
        将字典转换为指定类型的对象

        只有对象定义的属性才会被设置，字典中的额外字段会被忽略。

        Args:
            data: 源数据字典
            cls: 目标类类型

        Returns:
            转换后的对象实例，data为None时返回None

        Raises:
            BeanError: data不是字典类型时抛出
        """
        if data is None or isinstance(data, cls):
            return data

        if not isinstance(data, dict):
            raise BeanError(message=f"Fail to parse bean! {data}")

        bean_data = cls()
        bean_keys = bean_data.__dict__.keys()

        bean_dict = {}
        for key in bean_keys:
            if key in data:
                bean_dict[key] = data[key]

        bean_data.__dict__.update(bean_dict)
        return bean_data

    @staticmethod
    def parse2bean_list(
        data_list: Optional[List[Dict[str, Any]]],
        cls: Type[T]
    ) -> Optional[List[T]]:
        """
        将字典列表批量转换为对象列表

        Args:
            data_list: 源数据字典列表
            cls: 目标类类型

        Returns:
            转换后的对象列表，data_list为空时返回None

        Raises:
            BeanError: data_list不是列表类型时抛出
        """
        if data_list is None or len(data_list) == 0:
            return None

        if not isinstance(data_list, list):
            raise BeanError(message=f"Fail to parse bean list! {data_list}")

        bean_list: List[T] = []
        for data in data_list:
            bean_data = BeanUtil.parse2bean(data, cls)
            if bean_data is not None:
                bean_list.append(bean_data)

        return bean_list

    @staticmethod
    def parse_to_dict_list(data_list: Optional[List[Any]]) -> List[Dict[str, Any]]:
        """
        将对象列表转换为字典列表

        Args:
            data_list: 对象列表

        Returns:
            字典列表
        """
        if data_list is None or len(data_list) == 0:
            return []

        result_list: List[Dict[str, Any]] = []
        for line in data_list:
            if hasattr(line, "__dict__"):
                line = line.__dict__
            result_list.append(line)

        return result_list


class BaseBean:
    """
    基础Bean类

    提供通用的序列化和反序列化功能，可作为数据类的基类。

    Example:
        >>> class User(BaseBean):
        ...     def __init__(self):
        ...         self.name = ""
        ...         self.age = 0
        >>> user = User()
        >>> user.decode({"name": "Alice", "age": 30})
        >>> print(user)  # {"name": "Alice", "age": 30}
    """

    def __str__(self) -> str:
        """
        返回对象的字符串表示

        Returns:
            JSON格式的字符串
        """
        return json.dumps(self.__dict__, ensure_ascii=False, default=str)

    def to_dict(self) -> Dict[str, Any]:
        """
        将对象转换为字典

        Returns:
            对象属性字典
        """
        return self.__dict__.copy()

    def decode(self, data: Any) -> "BaseBean":
        """
        从数据源解码并更新对象属性

        Args:
            data: 数据源，可以是字典、JSON字符串或BaseBean对象

        Returns:
            更新后的对象自身

        Raises:
            BeanError: 数据格式无效时抛出
        """
        if isinstance(data, BaseBean):
            data = data.__dict__
        elif isinstance(data, str):
            try:
                data = json.loads(data)
            except json.JSONDecodeError:
                # 尝试替换单引号后解析
                data = json.loads(str(data).replace("'", '"'))

        if not isinstance(data, dict):
            raise BeanError(message=f"Fail to decode! {data}")

        bean_dict: Dict[str, Any] = {}
        bean_keys = self.__dict__.keys()
        for key in bean_keys:
            if key in data:
                bean_dict[key] = data[key]

        self.__dict__.update(bean_dict)
        return self
