"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from lib.core.SymbolTable import SymbolTable

from lib.core.SymbolData import (
    ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
)
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.core.LLVMTypeMapper import LLVMTypeMapper
from lib.core.SymbolUtils import IsTModule
from lib.includes import t


class TypeResolver:
    """解析从 AST 提取的原始符号中的类型信息"""

    def __init__(self, symbol_table: SymbolTable):
        self._symtab = symbol_table
        self._type_mapper = LLVMTypeMapper(symbol_table)
        # 本模块内已解析的 typedef: name → original_class（供同模块 typedef 间引用解析）
        self._resolved_typedefs: dict[str, str | None] = {}

    def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
        """解析所有类型信息，就地更新 ModuleSymbols"""
        # 构建 class_members 查找表（typedef Postdefinition 需要）
        class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes}

        # 解析 typedef（按顺序记录，供后续 typedef 引用同模块已解析的 typedef）
        td: TypedefSymbolData
        for td in module_symbols.typedefs:
            self._resolve_typedef(td, class_members)
            self._resolved_typedefs[td.name] = td.original_class

        # 解析函数签名
        func: FuncSymbolData
        for func in module_symbols.functions:
            self._resolve_function(func)

        # 解析 define 值
        define: DefineSymbolData
        for define in module_symbols.defines:
            self._resolve_define(define)

        return module_symbols

    # ------------------------------------------------------------------
    #  Typedef 解析
    # ------------------------------------------------------------------

    def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
        """解析单个 typedef 的类型信息"""
        is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef

        if is_postdef_with_typedef:
            self._resolve_postdef_typedef(td, class_members)
        elif td.has_ctypedef:
            self._resolve_ctypedef_typedef(td)
        else:
            # 无特殊注解的 typedef
            td.original_type_kind = None
            td.original_class = None

    def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]):
        """解析 Postdefinition + CTypedef 组合注解"""
        original_class: str | None = self._find_postdef_arg(td.annotation)
        if original_class and original_class in class_members:
            members_info: dict[str, CTypeInfo] = class_members[original_class]
            original_type_kind: str = 'struct'
            if original_class in self._symtab:
                orig_type_info: CTypeInfo = self._symtab[original_class]
                if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
                    if orig_type_info.type_cls is t.CStruct:
                        original_type_kind = 'struct'
                    elif orig_type_info.type_cls is t.CEnum:
                        original_type_kind = 'enum'
                    elif orig_type_info.type_cls is t.CUnion:
                        original_type_kind = 'union'
            td.original_type_kind = original_type_kind
            td.original_class = original_class
            td.members = members_info
        else:
            td.original_type_kind = None
            td.original_class = None

    def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
        """解析 CTypedef 注解"""
        base_type_name: str | None = self._find_base_type(td.annotation)
        _TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})

        if base_type_name == 'Callable':
            original_type: CTypeInfo = CTypeInfo()
            original_type.IsFuncPtr = True
            original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
            original_type.FuncPtrParams = []
            td.original_type_kind = 'typedef'
            td.original_class = original_type
        elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
            cname: str | None = CTypeHelper.GetCName(base_type_name)
            if cname:
                td.original_class = cname
            else:
                td.original_class = base_type_name
            td.original_type_kind = 'typedef'
        else:
            # 尝试从值表达式解析
            self._resolve_typedef_from_value(td)

    def _resolve_typedef_from_value(self, td: TypedefSymbolData):
        """从值表达式解析 typedef 类型

        BinOp（如 UINT | t.CPtr）优先于 _find_base_type 处理，
        因为 _find_base_type 是静态方法无法解析 Name 引用（如 UINT）。
        """
        if not td.value:
            td.original_type_kind = None
            td.original_class = None
            return

        # 优先处理 BinOp（_find_base_type 无法解析 Name 引用）
        if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
            left_type: str = self._resolve_type_expr(td.value.left)
            right_type: str = self._resolve_type_expr(td.value.right)
            is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
            if is_ptr_type:
                base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
                original_type: str = (base_name + ' *') if base_name else 'void *'
                td.original_class = original_type
                td.original_type_kind = 'typedef'
            elif left_type:
                td.original_class = left_type
                td.original_type_kind = 'typedef'
            elif right_type:
                td.original_class = right_type
                td.original_type_kind = 'typedef'
            else:
                td.original_type_kind = None
                td.original_class = None
            return

        # 非 BinOp：使用 _find_base_type
        value_base_type: str | None = self._find_base_type(td.value)
        _PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})

        if value_base_type and value_base_type not in _PTR_MODIFIERS:
            cname: str | None = CTypeHelper.GetCName(value_base_type)
            if cname:
                td.original_class = cname
            else:
                td.original_class = value_base_type
            td.original_type_kind = 'typedef'
            return

        if isinstance(td.value, ast.Name):
            ref_name: str = td.value.id
            # 先查本模块已解析的 typedef
            if ref_name in self._resolved_typedefs:
                ref_class: str | None = self._resolved_typedefs[ref_name]
                if ref_class:
                    td.original_class = ref_class
                    td.original_type_kind = 'typedef'
                    return
            # 再查 symtab（跨模块）
            if ref_name in self._symtab:
                ref_info: CTypeInfo = self._symtab[ref_name]
                if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
                    td.original_class = ref_info.OriginalType
                    td.original_type_kind = 'typedef'
                    return

        td.original_type_kind = None
        td.original_class = None

    def _resolve_type_expr(self, node: ast.AST) -> str:
        """解析类型表达式为 C 类型名字符串，优先查本模块已解析的 typedef

        解决同模块 typedef 间引用（如 UINTPTR = UINT | t.CPtr 中的 UINT）
        在 TypeResolver 阶段尚未插入 symtab 的问题。
        """
        if isinstance(node, ast.Name):
            if node.id in self._resolved_typedefs:
                return self._resolved_typedefs[node.id] or ''
        return self._type_mapper.resolve_typedef_value_type(node)

    # ------------------------------------------------------------------
    #  函数签名解析
    # ------------------------------------------------------------------

    def _resolve_function(self, func: FuncSymbolData):
        """解析函数的返回类型和参数类型"""
        func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node)
        # 同时解析为 CTypeInfo，保留符号性（LLVM 类型字符串 'i64' 不区分有无符号）
        if func.returns_node is not None:
            try:
                func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab)
            except Exception:
                func.ret_ctype = None
        func.param_types = []
        _arg_name: str
        annotation: ast.expr | None
        for _arg_name, annotation in func.params:
            if annotation:
                func.param_types.append(self._type_mapper.get_func_param_type_str(annotation))
            else:
                func.param_types.append('i8*')

    # ------------------------------------------------------------------
    #  Define 值解析
    # ------------------------------------------------------------------

    def _resolve_define(self, define: DefineSymbolData):
        """解析 define 常量值"""
        if define.value_node:
            define.value = self._symtab._eval_const_expr(define.value_node)

    # ------------------------------------------------------------------
    #  静态工具方法（原 _LoadSymbolsFromFile 中的闭包）
    # ------------------------------------------------------------------

    @staticmethod
    def _find_base_type(node: ast.AST | None) -> str | None:
        """从注解 AST 节点中查找基础类型名称"""
        if isinstance(node, ast.Attribute):
            if hasattr(node.value, 'id') and IsTModule(node.value.id):
                if node.attr == 'CPtr':
                    return 'ptr'
                return node.attr
        elif isinstance(node, ast.Subscript):
            if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable':
                return 'Callable'
        elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
            left_result: str | None = TypeResolver._find_base_type(node.left)
            if left_result == 'ptr':
                right_result: str | None = TypeResolver._find_base_type(node.right)
                return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
            if left_result == 'Callable':
                return 'Callable'
            right_result: str | None = TypeResolver._find_base_type(node.right)
            if right_result == 'ptr':
                return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
            if right_result == 'Callable':
                return 'Callable'
            # 类型拼接语义：CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
            long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
            if left_result in long_types and right_result in long_types:
                if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
                    return 'CUnsignedLongLong'
                return 'CLongLong'
            if left_result:
                return left_result
            if right_result:
                return right_result
        return None

    @staticmethod
    def _find_postdef_arg(node: ast.AST | None) -> str | None:
        """从注解 AST 节点中查找 Postdefinition 参数"""
        if isinstance(node, ast.Call):
            if isinstance(node.func, ast.Attribute):
                if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition':
                    if node.args and isinstance(node.args[0], ast.Name):
                        return node.args[0].id
        elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
            left_result: str | None = TypeResolver._find_postdef_arg(node.left)
            if left_result:
                return left_result
            right_result: str | None = TypeResolver._find_postdef_arg(node.right)
            if right_result:
                return right_result
        return None
