from ...common import AttributeManager

from typing import Any



class Node():
    __slots__ = ('__dict__', '__read_only')

    def __init__(
        self,
        config: dict[str, Any] = None,
        read_only: bool = None
    ):
        """
        Init Config[Node].

        :param config: config dict (default={})
        :param read_only: lock config alfer creation (default=False)
        """
        # params init -----
        if config is None:
            config = {}

        if read_only is None:
            read_only = False

        # init -----

        #__read_only__name: str = f'_{self.__class__.__name__}__read_only'
        #object.__setattr__(self, __read_only__name, False)
        AttributeManager.set_attribute(obj=self, attr='__read_only', value=False)

        for key, value in config.items():
            key_attribute = key.replace('-', '_')

            if isinstance(value, dict):
                self.__dict__[key_attribute] = Node(config=value, read_only=read_only)
            elif isinstance(value, list):
                self.__dict__[key_attribute] = [
                    Node(config=item, read_only=read_only) if isinstance(item, dict) else item
                    for item in value
                ]
            else:
                self.__dict__[key_attribute] = value

        #object.__setattr__(self, __read_only__name, read_only)
        AttributeManager.set_attribute(obj=self, attr='__read_only', value=read_only)
        pass


    def __getattr__(self, name: str) -> Any:
        if name not in self.__dict__:
            raise AttributeError(f'Config[Node] attribute "{name}" not found')
        return self.__dict__[name]


    def __setattr__(self, name: str, value: Any):
        if self.__read_only:
            raise RuntimeError(f'Config[Node] is read-only, attribute "{name}" cannot be changed')

        self.__dict__[name] = value
        pass


    def __delattr__(self, name: str):
        if self.__read_only:
            raise RuntimeError(f'Config[Node] is read-only, attribute "{name}" cannot be deleted')

        if name not in self.__dict__:
            raise AttributeError(f'Config[Node] attribute "{name}" not found')

        del self.__dict__[name]
        pass


    def __repr__(self) -> str:
        return f'{self.__dict__}'


    @property
    def as_dict(self) -> dict[str, Any]:
        """
        Conversion of Config[Node] to dict.

        :return:
        """

        config = {}

        for key, value in self.__dict__.items():
            if isinstance(value, Node):
                config[key] = value.as_dict
            elif isinstance(value, list):
                config[key] = [
                    item.as_dict if isinstance(item, Node) else item
                    for item in value
                ]
            else:
                config[key] = value

        return config

    pass
