from __future__ import annotations
from typing import Any, Dict, Optional

from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t


class SymbolNode:
    """符号表节点，类似 AST 节点的树形结构

    attributes 存储 CTypeInfo 对象，不再使用 TypeInfo
    """

    def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None):
        self.name: str = name
        self.type: str = NodeType
        self.lineno: int = lineno
        self.file: str = file
        self.parent: SymbolNode | None = parent
        self.children: Dict[str, SymbolNode] = {}
        self.attributes: CTypeInfo = CTypeInfo()
        self.attributes.Name = name
        self.attributes.Lineno = lineno

    def get(self, key: str, default: Any = None) -> Any:
        """获取属性值"""
        if hasattr(self.attributes, key):
            return getattr(self.attributes, key)
        return self.attributes._extra.get(key, default)

    def set(self, key: str, value: Any) -> None:
        """设置属性值"""
        if hasattr(self.attributes, key):
            attr: Any = getattr(type(self.attributes), key, None)
            if isinstance(attr, property) and attr.fset is None:
                return
            setattr(self.attributes, key, value)
        else:
            self.attributes._extra[key] = value

    def HasChild(self, name: str) -> bool:
        """检查是否有子节点"""
        return name in self.children

    def GetChild(self, name: str) -> Optional[SymbolNode]:
        """获取子节点"""
        return self.children.get(name)

    def AddChild(self, node: SymbolNode):
        """添加子节点"""
        node.parent = self
        self.children[node.name] = node

    def RemoveChild(self, name: str) -> bool:
        """删除子节点"""
        if name in self.children:
            del self.children[name]
            return True
        return False

    def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]:
        """根据路径查找节点，如 'test.ClassA'"""
        parts: list[str] = path.split(separator)
        current: SymbolNode = self

        for part in parts:
            if current.HasChild(part):
                current = current.GetChild(part)
            else:
                return None

        return current

    def ToDict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        result: dict[str, Any] = {
            'type': self.type,
            'lineno': self.lineno,
            'file': self.file,
        }
        # 序列化 CTypeInfo 属性
        attrs: CTypeInfo = self.attributes
        if attrs.BaseType:
            result['BaseType'] = str(attrs.BaseType)
        if attrs.PtrCount:
            result['PtrCount'] = attrs.PtrCount
        if attrs.IsTypedef:
            result['IsTypedef'] = True
        if attrs.IsStruct:
            result['IsStruct'] = True
        if attrs.IsEnum:
            result['IsEnum'] = True
        if attrs.IsUnion:
            result['IsUnion'] = True
        if attrs.IsFunction:
            result['IsFunction'] = True
        if attrs.IsVariable:
            result['IsVariable'] = True
        if attrs.IsDefine:
            result['IsDefine'] = True
        if attrs.OriginalType:
            result['OriginalType'] = str(attrs.OriginalType)
        if attrs._sm._extra:
            result.update(attrs._sm._extra)

        if self.children:
            result['children'] = {name: child.ToDict() for name, child in self.children.items()}

        return result

    @classmethod
    def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode:
        """从字典创建节点（兼容性）"""
        node = cls(name=name, NodeType=data.get('type', 'unknown'))
        node.lineno = data.get('lineno', 0)
        node.file = data.get('file', '')

        for key, value in data.items():
            if key not in ('type', 'lineno', 'file', 'children'):
                node.set(key, value)

        if 'children' in data:
            for ChildName, ChildData in data['children'].items():
                node.AddChild(cls.FromDict(ChildName, ChildData))

        return node

    @classmethod
    def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode:
        """创建成员节点（工厂函数）"""
        node = cls(name=name, NodeType='member', lineno=lineno, file=file)
        node.attributes = CTypeInfo()
        node.attributes.Name = name
        node.attributes.Lineno = lineno
        if TypeInfo is not None:
            node.attributes = TypeInfo
            node.attributes.Name = name
            node.attributes.Lineno = lineno
        else:
            if TypeName is not None:
                node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName)
            if IsPtr:
                node.attributes.PtrCount = 1
        if dims:
            node.attributes.ArrayDims = list(dims)
        return node

    @classmethod
    def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode:
        """创建类节点（工厂函数）"""
        node: SymbolNode = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file)
        node.attributes = CTypeInfo()
        node.attributes.Name = name
        node.attributes.Lineno = lineno
        node.attributes.IsCpythonObject = IsCpythonObject
        node.attributes.IsPacked = IsPacked
        if members:
            for MemberName, MemberInfo in members.items():
                if isinstance(MemberInfo, CTypeInfo):
                    node.attributes.Members[MemberName] = MemberInfo
                elif isinstance(MemberInfo, dict):
                    CTypeMember: CTypeInfo = CTypeInfo()
                    type_str: str = MemberInfo.get('type', 'int')
                    IsPtr: bool = MemberInfo.get('IsPtr', False)
                    if isinstance(type_str, str):
                        try:
                            resolved: CTypeInfo | None = CTypeInfo.FromTypeName(type_str)
                            if resolved and resolved.BaseType:
                                CTypeMember = resolved
                            else:
                                CTypeMember.BaseType = t.CInt()
                        except Exception:
                            CTypeMember.BaseType = t.CInt()
                    else:
                        CTypeMember.BaseType = t.CInt()
                    if IsPtr and not CTypeMember.IsPtr:
                        CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1)
                    node.attributes.Members[MemberName] = CTypeMember
        if TypeKind == 'struct':
            node.attributes.IsStruct = True
        elif TypeKind == 'enum':
            node.attributes.IsEnum = True
        elif TypeKind == 'union':
            node.attributes.IsUnion = True
        elif TypeKind == 'typedef':
            node.attributes.IsTypedef = True
        elif TypeKind == 'exception':
            node.attributes.IsExceptionClass = True
        return node

    @classmethod
    def CreateTypedef(cls, name: str, OriginalType: CTypeInfo | str | None, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode:
        node: SymbolNode = cls(name=name, NodeType='typedef', lineno=lineno, file=file)
        node.attributes = CTypeInfo()
        node.attributes.Name = name
        node.attributes.Lineno = lineno
        node.attributes.IsTypedef = True
        if isinstance(OriginalType, CTypeInfo):
            node.attributes.OriginalType = OriginalType
        elif isinstance(OriginalType, str):
            node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None
        else:
            node.attributes.OriginalType = OriginalType
        return node

    @classmethod
    def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode:
        """创建匿名类型节点（工厂函数）"""
        NodeType: type = t.CUnion if IsUnion else t.CStruct
        node: SymbolNode = cls(name=name, NodeType=NodeType, lineno=lineno, file=file)
        node.attributes = CTypeInfo()
        node.attributes.Name = name
        node.attributes.Lineno = lineno
        node.attributes.IsAnonymous = True
        if IsUnion:
            node.attributes.IsUnion = True
        else:
            node.attributes.IsStruct = True
        return node

    @classmethod
    def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode:
        """创建模块节点（工厂函数）"""
        return cls(name=name, NodeType='module', lineno=lineno, file=file)
