from typing import Any
from core.defines import Dict, List
import json
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import core.logger as logger
log = logger.get_logger()

class BaseConfig():
    """
    所有配置类的基类, 所有配置类都继承自该类
    提供配置的统一使用方式：
    1. 基类通过 __getattr__ 方法，实现通过点号访问配置
    2. 基类通过 __setattr__ 方法，实现通过点号设置配置
    3. 基类通过 __getitem__ 方法，实现通过索引访问配置
    4. 基类通过 __setitem__ 方法，实现通过索引设置配置
    5. 基类通过 __delitem__ 方法，实现通过索引删除配置
    6. 基类通过 __len__ 方法，实现获取配置的长度
    7. 基类通过 __str__ 方法，实现获取配置的json字符串
    8. 基类通过 __repr__ 方法，实现获取配置的json字符串
    9. 子类通过 check 方法，实现检查配置是否合法
    10. 子类通过 @AutoInstanceDecorator 装饰器，自动将类替换为它的实例
    """
    # 存储原始配置数据，子类复写该属性以表明其配置，其可以是列表或字典
    _config = None
    _list = List() # 用于存储配置是一个list的形式
    _dict = Dict() # 配置的key-value形式，以及list也会扩展为dict存储，方便使用
    _value = None # 配置仅仅是一个value的情况
    # 用于存储实例, 单例模式，防止重复实例化 子类无须操作该属性
    _instance = None

    def __new__(cls):
        """
        如果实例已经存在，则直接返回实例，实现单例模式。
        """
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    def _value_raise(self):
        if self._value is not None:
            raise AttributeError(f"{self.__class__.__name__} not support this method")
    def __init__(self) -> None:
        """
        初始化实例的_list和_dict，
        并将其绑定到类属性上，
        """
        # log.info(f"Load config: {self.__class__.__name__}")
        # 获取子类的 _config 属性
        _config = getattr(self.__class__, '_config', None)
        if _config is None:
            raise ValueError(f"_config must be defined in {self.__class__.__name__}")
        self._list = List()
        self._dict = Dict()
        if isinstance(_config, list):
            self._list = List(_config)
            for key in self._list:
                # 将列表项同时添加到属性中 以便于通过Dot方式访问
                self._dict[key] = key
        elif isinstance(_config, dict):
            self._dict = Dict(_config)
        # 配置是单个值的情况
        elif isinstance(_config, (int, float, str, bool)):
            self._value = _config
            self._dict = Dict({str(_config) : _config})
            self._list = List([_config])
        else:
            raise ValueError(f"{self.__class__.__name__} _config must be a list or dict")
        log.debug(f"Load config cnt: {len(self._dict):3} => {self.__class__.__name__}")

    def __getattr__(self, key):
        """
        当通过类属性方式访问不存在的属性时，尝试从 _dict 中获取
        """
        return self[key]

    def __setattr__(self, key, value):
        """
        当通过类属性方式设置值时，同时更新 _dict
        """
        # log.info(f"setattr: {self.__class__.__name__}, key: {key}, value: {value}")
        #  如果是非字符串，或者是非_开头的字符串，则将其添加到_dict中
        if not isinstance(key, str) or not key.startswith('_'):
            self[key] = value
        # 如果key是字符串且是合法的标识符，则将其添加到类属性中
        elif isinstance(key, str):
            super().__setattr__(key, value)
        else:
            raise AttributeError(f"Attribute {key} is not a valid identifier")
    def __delattr__(self, key:str):
        """
        当通过类属性方式删除值时，同时删除 _dict 中的值
        """
        del self[key]

    def items(self):
        return self._dict.items()

    def get(self, key=None, default=None):
        """
        获取配置值
        """
        if key is None:
            if self._value is not None:
                return self._value
            else:
                raise KeyError(f"{self.__class__.__name__} must set key to get")
        return self[key] if key in self else default

    def __getitem__(self, key):
        """
        当通过索引方式访问值:
        1. 如果key是整数，按列表方式访问
        2. 如果key是字符串，按字典方式访问
        3. 如果key既不是整数也不是字符串，抛出TypeError
        例如:
        config = MyConfig()
        print(config[0])
        print(config["key"])
        """
        if isinstance(key, int):
            return self._list[key]
        elif isinstance(key, str):
            # 如果key中包含/，说明可能是个路径。返回key本身
            # 因为有些配置直接将路径作为配置项
            if '/' in key:
                return key
            else:
                # 如果 key 是字符串，按字典方式访问
                return self._dict[key]
        else:
            raise TypeError("Key must be either an integer or a string")

    def __setitem__(self, key, value):
        """
        当通过索引方式设置值:
        1. 如果key是整数，按列表方式设置
        2. 如果key是字符串，按字典方式设置
        3. 如果key既不是整数也不是字符串，抛出TypeError
        例如:
        config = MyConfig()
        config[0] = "value"
        config["key"] = "value"
        """
        # log.info(f"setitem: {self.__class__.__name__}, key: {key}, value: {value}")
        if isinstance(key, int):
            old_value = self._list[key]
            self._list[key] = value
            self._dict.pop(old_value)
            key = value
        elif isinstance(key, str):
            if self._list:
                # 我们会将新的key和value同时添加到_list和_dict中 确保key和value是相同的
                if key in self._list:
                    self._list[self._list.index(key)] = value
                    self._dict.pop(key)
                    key = value
                else:
                    self._list.append(key)
        else:
            raise TypeError("Key must be either an integer or a string")
        self._dict[key] = value
        # log.info(f"setitem ok: {self.__class__.__name__}, key: {key}, value: {self._dict[key]}")

    def __delitem__(self, key):
        """
        当通过索引方式删除值:
        1. 如果key是整数，按列表方式删除
        2. 如果key是字符串，按字典方式删除
        3. 如果key既不是整数也不是字符串，抛出TypeError
        例如:
        config = MyConfig()
        del config[0]
        del config["key"]
        """
        if isinstance(key, int):
            self.__delattr__(self._list[key])
        elif isinstance(key, str):
            # 如果 key 是字符串，按字典方式删除
            if key not in self._dict:
                raise KeyError(f"Key {key} not found in the dictionary")
            self._dict.pop(key)
            if key in self._list:
                self._list.pop(self._list.index(key))
        else:
            raise TypeError("Key must be either an integer or a string")

    def __contains__(self, key):
        """
        检查配置是否包含某个key
        """
        return key in self._dict
    def __iter__(self):
        """
        返回配置的迭代器
        """
        if self._value is not None:
            yield self._value
        elif self._list:
            yield from self._list
        elif self._dict:
            yield from self._dict
        else:
            raise StopIteration
    def __len__(self):
        """
        返回配置的长度
        """
        if self._value is not None:
            return 1
        elif self._list:
            return len(self._list)
        elif self._dict:
            return len(self._dict)
        else:
            return 0

    def __str__(self):
        """
        返回对象的字符串表示，使用json 风格来呈现
        """
        # log.info(f"str: {self.__class__.__name__}, len: {len(self._list)}")
        if self._value is not None:
            return f"{self._value}"
        elif self._list:
            return json.dumps(self._list, indent=4)
        elif self._dict:
            return json.dumps(self._dict, indent=4)
        else:
            return ""

    def __repr__(self):
        """
        返回对象的字符串表示，使用json 风格来呈现
        """
        return self.__str__()
    
    def __eq__(self, other):
        """
        实现对象的相等比较
        1. 如果other是字符串，且self._value不为None，则与_value进行比较
        2. 如果other是BaseConfig实例：
           - 如果两者都有_value，则比较_value
           - 如果两者都有_list，则比较_list
           - 如果两者都有_dict，则比较_dict
        3. 如果other是列表，且self._list不为空，则与_list进行比较
        4. 如果other是字典，且self._dict不为空，则与_dict进行比较
        5. 否则，使用默认的比较行为
        """
        # 处理字符串比较
        if isinstance(other, (int, float, str, bool)) and self._value is not None:
            return self._value == other
        # 处理BaseConfig实例比较
        elif isinstance(other, BaseConfig):
            if self._value is not None and other._value is not None:
                return self._value == other._value
            elif self._list and other._list:
                return self._list == other._list
            elif self._dict and other._dict:
                return self._dict == other._dict
            else:
                return False
        elif isinstance(other, list) and self._list:
            return self._list == other
        elif isinstance(other, dict) and self._dict:
            return self._dict == other
        else:
            return super().__eq__(other)
    
    def check(self) -> bool:
        """检查配置是否合法
        Returns:
            bool: 如果配置合法，返回True，否则返回False
        子类可以复写该方法，以检查配置是否合法
        """
        return True
    
    def update(self, _config):
        """更新配置
        Args:
            _config (dict): 需要更新的配置

        Raises:
            ValueError: 如果_config不是字典或列表
        """
        if isinstance(_config, dict):
            for key, value in _config.items():
                self[key] = value
        elif isinstance(_config, list):
            for item in _config:
                self[item] = item
        elif isinstance(_config, (int, float, str, bool)):
            self._value = _config
            self._dict = Dict({str(_config) : _config})
            self._list = List([_config])
        else:
            raise ValueError(f"_config type {type(_config)} is not support!")
    
    def _clean(self):
        """清除所有配置
        """
        [self.__delitem__(_) for _ in self._dict.copy()]
    
    def update_from_extra(self, new_data:Any):
        """ 从json中更新数据，默认行为是加载，子类可以重载该函数使得其可以具备不同的行为

        Args:
            new_data (Any): 带有直接属于该配置的数据
        """
        self.load(new_data)

    def load(self, new_data:Any):
        """ 加载数据：会先清除当前配置，然后更新配置

        Args:
            new_data (Any): 带有直接属于该配置的数据
        例如：
        ```python
        MyConfig.load({"key1": "value1", "key2": "value2"})
        MyConfig1.load([1, 2, 3])
        MyConfig2.load(123)
        MyConfig3.load("123")
        MyConfig4.load(True)
        ```
        """
        
        if not isinstance(new_data, (dict, list, int, float, str, bool)):
            raise ValueError(f"Datatype {type(new_data)} is not support!")
        self._clean()
        self.update(new_data)

    def remove(self, new_data: Any):
        """删除数据
        """
        if isinstance(new_data, (list, dict)):
            for item in new_data:
                del self[item]
        elif isinstance(new_data, (int, float, str, bool)):
            del self[new_data]
        else:
            raise ValueError(f"Datatype {type(new_data)} is not support!")

def AutoInstanceDecorator(cls):
    """自动实例化装饰器：自动将类替换为它的实例，实现类名访问即实例访问，
    例如：
    ```python
    print(MyConfig.key)
    ```
    等价于
    ```python
    config = MyConfig()
    print(config["key"])
    ```
    """
    instance = cls()  # 创建实例
    return instance  # 返回实例，替换原始类