from __future__ import annotations

import ast
import os
import importlib
import types
from typing import Any

import lib._bootstrap  # noqa: F401  设置 sys.path（项目根 + lib/includes）

from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
from lib.includes import t
from lib.includes.t import CType, CEnum
from lib.constants.config import mode as _config_mode
from lib.core.VLogger import get_logger as _vlog


class AnnotationLoaderMixin:
    """注解模块加载 Mixin

    提供注解模块/文件的加载与符号表注册能力。
    """

    def _LoadAnnotationModule(self, ModuleName: str, library_name: str | None = None, parse_method: str = 'auto') -> int:
        """加载注解模块并将 CType 子类注册为 typedef

        支持两种模式：
        1. AST 模式：如果 ModuleName 是文件路径，解析文件提取 CType
        2. importlib 模式：如果 ModuleName 是模块名，导入模块提取 CType

        Args:
            ModuleName: 模块名或文件路径
            library_name: 手动指定的库名称，用于注册到符号表。如果为 None，则从 ModuleName 推断
            parse_method: 解析方法，可选值：
                - 'auto': 自动检测（默认）
                - 'file': 强制使用 AST 模式（文件路径）
                - 'module': 强制使用 importlib 模式（模块名）
        """
        def register_to_symboltable(module: types.ModuleType, lib_name: str | None = None, source_file: str | None = None) -> int:
            """将模块中的 CType 子类和 CEnum 类注册到符号表"""
            count: int = 0
            for AttrName in dir(module):
                attr: type = getattr(module, AttrName)
                # 优先检查是否是 CEnum 子类（枚举）
                if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
                    # 注册枚举类型
                    EnumNode: CTypeInfo = CTypeInfo()
                    EnumNode.Name = AttrName
                    EnumNode.BaseType = t.CEnum()
                    EnumNode.IsEnum = True
                    EnumNode.set('enum_class', attr)
                    EnumNode.set('source', 'annotation_module')
                    EnumNode.library_name = lib_name
                    EnumNode.file = source_file
                    self.SymbolTable.insert(AttrName, EnumNode)
                    if lib_name:
                        FullName: str = f'{lib_name}.{AttrName}'
                        full_EnumNode: CTypeInfo = CTypeInfo()
                        full_EnumNode.Name = FullName
                        full_EnumNode.IsEnum = True
                        full_EnumNode.set('enum_class', attr)
                        full_EnumNode.set('source', 'annotation_module')
                        full_EnumNode.library_name = lib_name
                        full_EnumNode.file = source_file
                        self.SymbolTable.insert(FullName, full_EnumNode)
                    # 枚举成员也需要注册
                    for MemberName in dir(attr):
                        if not MemberName.startswith('_'):
                            member: int = getattr(attr, MemberName, None)
                            if isinstance(member, int):
                                MemberNode: CTypeInfo = CTypeInfo()
                                MemberNode.Name = MemberName
                                MemberNode.BaseType = t.CEnum(AttrName)
                                MemberNode.value = member
                                MemberNode.EnumName = AttrName
                                MemberNode.library_name = lib_name
                                MemberNode.IsEnumMember = True
                                self.SymbolTable.insert(MemberName, MemberNode)
                                self.SymbolTable.insert(f"{AttrName}.{MemberName}", MemberNode)
                                self.SymbolTable.insert(f"{AttrName}_{MemberName}", MemberNode)
                                if lib_name:
                                    self.SymbolTable.insert(f"{lib_name}.{AttrName}.{MemberName}", MemberNode)
                                    self.SymbolTable.insert(f"{lib_name}_{AttrName}_{MemberName}", MemberNode)
                    count += 1
                # 检查是否是 CType 子类（typedef 别名）
                elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType:
                    # 继承 CType 的类是类型别名（typedef），不是结构体
                    # 使用手动指定的库名称作为前缀
                    if lib_name:
                        FullName: str = f'{lib_name}.{AttrName}'
                    else:
                        FullName = AttrName
                    # 同时注册带前缀和不带前缀的名称（都是 typedef 别名）
                    TypedefNode: CTypeInfo = CTypeInfo()
                    TypedefNode.Name = AttrName
                    TypedefNode.IsTypedef = True
                    TypedefNode.OriginalType = attr.__name__
                    TypedefNode.set('source', 'annotation_module')
                    TypedefNode.library_name = lib_name
                    TypedefNode.file = source_file
                    self.SymbolTable.insert(AttrName, TypedefNode)
                    if lib_name and FullName != AttrName:
                        FullTypedef_node: CTypeInfo = CTypeInfo()
                        FullTypedef_node.Name = FullName
                        FullTypedef_node.IsTypedef = True
                        FullTypedef_node.OriginalType = attr.__name__
                        FullTypedef_node.set('source', 'annotation_module')
                        FullTypedef_node.library_name = lib_name
                        FullTypedef_node.file = source_file
                        self.SymbolTable.insert(FullName, FullTypedef_node)
                    count += 1
                # 检查是否是下划线前缀的 CType 子类（如 _CTypedef -> CTypedef）
                elif AttrName.startswith('_') and len(AttrName) > 1:
                    PublicName: str = AttrName[1:]
                    PublicAttr: type | None = getattr(module, PublicName, None)
                    if PublicAttr is not None and not isinstance(attr, type):
                        continue
                    if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType:
                        if not self.SymbolTable.has(PublicName):
                            if lib_name:
                                FullName: str = f'{lib_name}.{PublicName}'
                            else:
                                FullName = PublicName
                            TypedefNode: CTypeInfo = CTypeInfo()
                            TypedefNode.Name = PublicName
                            TypedefNode.IsTypedef = True
                            TypedefNode.OriginalType = attr.__name__
                            TypedefNode.set('source', 'annotation_module')
                            TypedefNode.library_name = lib_name
                            TypedefNode.file = source_file
                            self.SymbolTable.insert(PublicName, TypedefNode)
                            if lib_name and FullName != PublicName:
                                FullTypedef_node: CTypeInfo = CTypeInfo()
                                FullTypedef_node.Name = FullName
                                FullTypedef_node.IsTypedef = True
                                FullTypedef_node.OriginalType = attr.__name__
                                FullTypedef_node.set('source', 'annotation_module')
                                FullTypedef_node.library_name = lib_name
                                FullTypedef_node.file = source_file
                                self.SymbolTable.insert(FullName, FullTypedef_node)
                            count += 1
            return count

        # 确定解析方法
        use_file_mode: bool = False
        if parse_method == 'file':
            use_file_mode = True
        elif parse_method == 'module':
            use_file_mode = False
        else:  # auto
            use_file_mode = os.path.isfile(ModuleName)

        # 确定库名称
        lib_name: str | None = library_name
        if lib_name is None:
            if use_file_mode:
                # 从文件路径推断库名称
                lib_name = os.path.splitext(os.path.basename(ModuleName))[0]
            else:
                # 模块名就是库名称
                lib_name = ModuleName

        # 根据解析方法加载模块
        if use_file_mode:
            # AST 模式：使用 AST 解析文件，不执行代码
            try:
                # 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments
                saved_embedded: dict = self.EmbeddedAssignments.copy()
                saved_typedef: dict = self.TypedefAssignments.copy()

                # 清空 PD 收集（注解文件不应该收集 PD 语句）
                self.EmbeddedAssignments = {}
                self.TypedefAssignments = {}

                # 直接调用 ParsePythonFile 解析文件提取类型信息
                # 注意：这不会执行任何 Python 代码，只是解析 AST
                # UpdateCurrentFile=False 表示不修改 CurrentFile
                self.ParsePythonFile(ModuleName, UpdateCurrentFile=False)

                # 恢复主代码文件的 PD 收集
                self.EmbeddedAssignments = saved_embedded
                self.TypedefAssignments = saved_typedef

                # 从文件名推断类型前缀（如 test_t -> test_t.xxx）
                TypePrefix: str = lib_name
                count: int = 0

                # 检查符号表中新增的类型（注解文件解析后的所有 struct 类型）
                # 需要检查这些类型是否继承自 CType，如果是则是 typedef 别名
                new_types: list[str] = []
                for TypeName, TypeInfo in self.SymbolTable.items():
                    if TypeInfo.IsStruct:
                        new_types.append(TypeName)

                # 再次遍历 AST，检测继承自 CType 的类
                try:
                    with open(ModuleName, 'r', encoding='utf-8') as f:
                        ann_content: str = f.read()
                    ann_tree: ast.Module = ast.parse(ann_content)
                    for node in ann_tree.body:
                        if isinstance(node, ast.ClassDef):
                            ClassName: str = node.name
                            # 检查是否有基类
                            for base in node.bases:
                                if isinstance(base, ast.Name) and base.id == 'CType':
                                    # 这个类继承自 CType，是 typedef 别名
                                    # 更新符号表中的类型为 typedef
                                    if self.SymbolTable.has(ClassName):
                                        TypedefNode: CTypeInfo = CTypeInfo()
                                        TypedefNode.Name = ClassName
                                        TypedefNode.IsTypedef = True
                                        TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
                                        TypedefNode.set('source', 'annotation_module')
                                        TypedefNode.set('is_ctype_subclass', True)
                                        self.SymbolTable.insert(ClassName, TypedefNode)
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception")

                # 为所有新增的类型添加库前缀和 source 标记
                for TypeName in new_types:
                    # 添加带前缀的类型名
                    FullName: str = f'{TypePrefix}.{TypeName}'
                    TypeInfo: CTypeInfo | dict[str, Any] = self.SymbolTable[TypeName].copy()
                    TypeInfo['source'] = 'annotation_module'
                    TypeInfo['original_name'] = TypeName
                    self.SymbolTable.insert(FullName, TypeInfo)
                    count += 1

                # 再次遍历 AST，查找注解文件中的 typedef 语句（AnnAssign with t.CTypedef）
                # 注意：必须在类定义处理完之后再处理 typedef
                typedef_annots: list[tuple[str, str]] = []
                # 查找 CEnum 成员变量（AnnAssign with t.CEnum | t.State 或 t.CEnum）
                cEnumMembers: list[tuple[str, int | None]] = []
                try:
                    with open(ModuleName, 'r', encoding='utf-8') as f:
                        ann_content: str = f.read()
                    ann_tree: ast.Module = ast.parse(ann_content)
                    for node in ann_tree.body:
                        # 检测 xxx: t.CEnum 形式的枚举成员变量
                        if isinstance(node, ast.AnnAssign):
                            if isinstance(node.target, ast.Name) and node.annotation:
                                TargetName: str = node.target.id
                                # 检查注解是否是 BinOp (Union) 或直接是 Attribute
                                IsCenum: bool = False
                                if isinstance(node.annotation, ast.BinOp):
                                    # 检查是否包含 CEnum
                                    if AnnotationContainsName(node.annotation, 'CEnum'):
                                        IsCenum = True
                                elif isinstance(node.annotation, ast.Attribute):
                                    # 直接是 t.CEnum
                                    if node.annotation.attr == t.CEnum.__name__:
                                        IsCenum = True

                                if IsCenum:
                                    # 检查值是否是 Constant (枚举成员值)
                                    if node.value and isinstance(node.value, ast.Constant):
                                        value: int | str | float | None = node.value.value
                                    else:
                                        value = None
                                    cEnumMembers.append((TargetName, value))
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception")

                # 处理 CEnum 成员变量
                for TargetName, value in cEnumMembers:
                    # 注册枚举成员
                    MemberNode: CTypeInfo = CTypeInfo()
                    MemberNode.Name = TargetName
                    MemberNode.BaseType = t.CEnum(TypePrefix)
                    MemberNode.value = value
                    MemberNode.EnumName = TypePrefix
                    MemberNode.library_name = TypePrefix
                    MemberNode.IsEnumMember = True
                    self.SymbolTable.insert(TargetName, MemberNode)
                    self.SymbolTable.insert(f"{TypePrefix}.{TargetName}", MemberNode)
                    self.SymbolTable.insert(f"{TypePrefix}_{TargetName}", MemberNode)

                try:
                    with open(ModuleName, 'r', encoding='utf-8') as f:
                        ann_content: str = f.read()
                    ann_tree: ast.Module = ast.parse(ann_content)
                    for node in ann_tree.body:
                        # 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句
                        if isinstance(node, ast.AnnAssign):
                            if isinstance(node.target, ast.Name) and node.annotation and node.value:
                                TargetName: str = node.target.id
                                # 检查注解是否是 t.CTypedef
                                if isinstance(node.annotation, ast.Attribute):
                                    if isinstance(node.annotation.value, ast.Name):
                                        if IsTModule(node.annotation.value.id) and node.annotation.attr == 'CTypedef':
                                            # 检查值是否是 Name
                                            if isinstance(node.value, ast.Name):
                                                original_name: str = node.value.id
                                                typedef_annots.append((TargetName, original_name))
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception")

                # 处理 typedef 注解
                for TargetName, original_name in typedef_annots:
                    # 检查原始类型是否在符号表中（带前缀或不带前缀）
                    orig_with_prefix: str = f'{TypePrefix}.{original_name}'
                    if self.SymbolTable.has(orig_with_prefix):
                        # 添加带前缀的 typedef 别名
                        FullTypedef_name: str = f'{TypePrefix}.{TargetName}'
                        TypedefNode: CTypeInfo = CTypeInfo()
                        TypedefNode.Name = FullTypedef_name
                        TypedefNode.IsTypedef = True
                        orig_entry: CTypeInfo | dict[str, Any] = self.SymbolTable.lookup(orig_with_prefix)
                        orig_type_str: str = f'struct {original_name}'
                        if isinstance(orig_entry, dict):
                            if orig_entry.get('type') == 'typedef':
                                orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}')
                            elif orig_entry.get('type') == 'enum':
                                orig_type_str = f'enum {original_name}'
                        elif orig_entry.IsTypedef:
                            orig_type_str = orig_entry.OriginalType or f'struct {original_name}'
                        elif orig_entry.IsEnum:
                            orig_type_str = f'enum {original_name}'
                        TypedefNode.OriginalType = orig_type_str
                        TypedefNode.set('source', 'annotation_module')
                        TypedefNode.set('original_name', TargetName)
                        self.SymbolTable.insert(FullTypedef_name, TypedefNode)
                        count += 1

                self.AnnotationModules.add(lib_name)
                return count
            except Exception as e:
                # 恢复 PD 收集
                self.EmbeddedAssignments = saved_embedded
                self.TypedefAssignments = saved_typedef
                self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}")
                return 0
        else:
            # importlib 模式：导入模块
            try:
                module: types.ModuleType = importlib.import_module(ModuleName)
                count: int = register_to_symboltable(module, lib_name, None)
                self.AnnotationModules.add(lib_name)
                return count
            except ImportError:
                self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}")
                return 0
            except Exception as e:
                self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}")
                return 0

    def _LoadAnnotationFiles(self, FilePaths: list[str | tuple]) -> None:
        """加载多个注解文件并注册到符号表

        Args:
            FilePaths: 文件路径列表，每个元素可以是：
                - str: 文件路径或模块名
                - tuple: (path, options) 或 (path, library_name, parse_method)
        """
        for item in FilePaths:
            if isinstance(item, tuple):
                if len(item) >= 3:
                    path: str
                    library_name: str
                    parse_method: str
                    path, library_name, parse_method = item[:3]
                    count: int = self._LoadAnnotationModule(path, library_name, parse_method)
                elif len(item) == 2:
                    path: str
                    library_name: str
                    path, library_name = item
                    count: int = self._LoadAnnotationModule(path, library_name, 'auto')
                else:
                    count: int = self._LoadAnnotationModule(item)
            else:
                count: int = self._LoadAnnotationModule(item)

    # 别名，保持向后兼容
    LoadAnnotationFiles = _LoadAnnotationFiles
