"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器

从 SymbolTable 中提取的类型解析逻辑，职责单一：
将 Python AST 注解节点翻译为 LLVM IR 类型字符串（如 'i32', 'i8*', '{ i32, i8* }'）。

原 SymbolTable 上的 4 个方法：
  - _GetLLVMTypeStr      → LLVMTypeMapper.get_llvm_type_str
  - _GetFuncRetTypeStr   → LLVMTypeMapper.get_func_ret_type_str
  - _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str
  - _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type
"""
from __future__ import annotations

import ast
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from lib.core.SymbolTable import SymbolTable

from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry


class LLVMTypeMapper:
    """AST 注解节点 → LLVM IR 类型字符串 映射器"""

    def __init__(self, symtab: SymbolTable):
        self._symtab = symtab

    # ==================================================================
    #  公共 API
    # ==================================================================

    def get_llvm_type_str(self, node: ast.AST | None) -> str:
        """将 AST 注解节点转换为 LLVM IR 类型字符串"""
        if node is None:
            self._symtab.diagnostics.warn('', 0, "类型注解为 None，回退到 i32")
            return 'i32'
        if isinstance(node, ast.Name):
            return self._resolve_name(node)
        elif isinstance(node, ast.Attribute):
            return self._resolve_attribute(node)
        elif isinstance(node, ast.Subscript):
            return self._resolve_subscript(node)
        elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
            return self._resolve_bitor(node)
        elif isinstance(node, ast.Constant):
            if isinstance(node.value, bool):
                return 'i8'
            return 'i32'
        elif isinstance(node, ast.Call):
            return self._resolve_call(node)
        self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__}，回退到 i32")
        return 'i32'

    def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
        """提取函数返回类型的 LLVM 字符串"""
        if returns_node is None:
            return 'i32'
        if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
            left_str: str = self.get_llvm_type_str(returns_node.left)
            right_str: str = self.get_llvm_type_str(returns_node.right)
            if right_str and right_str.endswith('*'):
                return right_str
            if left_str and left_str.endswith('*'):
                return left_str
            if left_str and left_str not in ('i32', 'void', 'i64'):
                return left_str
            if right_str and right_str not in ('i32', 'void', 'i64'):
                return right_str
            return left_str
        result: str = self.get_llvm_type_str(returns_node)
        return result if result else 'i32'

    def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
        """提取函数参数类型的 LLVM 字符串"""
        if annotation_node is None:
            return 'i8*'
        if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
            left_str: str = self.get_llvm_type_str(annotation_node.left)
            right_str: str = self.get_llvm_type_str(annotation_node.right)
            if right_str and right_str.endswith('*'):
                return right_str
            if left_str and left_str.endswith('*'):
                return left_str
            if right_str and right_str not in ('i32', 'void', 'i64'):
                return right_str
            if left_str and left_str not in ('i32', 'void', 'i64'):
                return left_str
            return right_str if right_str else left_str
        result: str = self.get_llvm_type_str(annotation_node)
        return result if result else 'i8*'

    def resolve_typedef_value_type(self, node: ast.AST | None) -> str:
        """解析 typedef 值表达式的 C 类型字符串"""
        if node is None:
            return ''
        if isinstance(node, ast.Name):
            if node.id in self._symtab:
                Entry: CTypeInfo = self._symtab[node.id]
                if Entry.IsTypedef and Entry.OriginalType:
                    return Entry.OriginalType
            return ''
        if isinstance(node, ast.Attribute):
            if isinstance(node.value, ast.Name) and IsTModule(node.value.id):
                # 直接判断属性名是否为 CPtr（消除对 CName=='*' 的依赖）
                if node.attr == 'CPtr':
                    return 'ptr'
                CName: str | None = CTypeHelper.GetCName(node.attr)
                if CName == 'CPtr':
                    return 'ptr'
                if CName:
                    return CName
            return ''
        if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
            left_str: str = self.resolve_typedef_value_type(node.left)
            right_str: str = self.resolve_typedef_value_type(node.right)
            if right_str == 'ptr' or (right_str and right_str.endswith('*')):
                base: str = left_str if left_str and left_str != 'ptr' else ''
                return base + ' *' if base else 'void *'
            if left_str == 'ptr' or (left_str and left_str.endswith('*')):
                base: str = right_str if right_str and right_str != 'ptr' else ''
                return base + ' *' if base else 'void *'
            if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
                return right_str
            if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
                return left_str
            return left_str if left_str else right_str
        return ''

    # ==================================================================
    #  内部解析方法
    # ==================================================================

    def _ctype_to_llvm_str(self, info: CTypeInfo) -> str:
        """从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。

        void* 在 LLVM IR 中归一化为 i8*；struct/enum/union 等非基础类型返回空字符串。
        """
        if not info or not info.BaseType:
            return ''
        base_type = info.BaseType
        base_llvm: str = ''
        if isinstance(base_type, type) and issubclass(base_type, _t.CType):
            base_llvm = CTypeRegistry.CTypeToLLVM(base_type)
        elif isinstance(base_type, _t.CType):
            base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type))
        if not base_llvm:
            return ''
        if info.PtrCount > 0:
            if base_llvm == 'void':
                return 'i8*'
            return base_llvm + '*' * info.PtrCount
        return base_llvm

    def _ctype_str_to_llvm(self, type_str: str) -> str:
        """将 C 类型名字符串（如 'CUnsignedInt *'）转换为 LLVM 类型字符串（如 'i32*'）

        支持：
        - C 类名：'CUnsignedInt' → 'i32'，'CChar' → 'i8'
        - 指针：'CUnsignedInt *' → 'i32*'，'void *' → 'i8*'
        - 已是 LLVM 类型：'i32' → 'i32'，'i8*' → 'i8*'
        无法识别返回空字符串。
        """
        s: str = type_str.strip()
        ptr_count: int = 0
        while s.endswith('*'):
            ptr_count += 1
            s = s[:-1].strip()
        base_llvm: str = ''
        if s in ('void', 'CVoid'):
            base_llvm = 'void'
        else:
            base_llvm = CTypeRegistry.NameToLLVM(s)
            if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'):
                base_llvm = s
        if not base_llvm:
            return ''
        if ptr_count > 0:
            if base_llvm == 'void':
                return 'i8*'
            return base_llvm + '*' * ptr_count
        return base_llvm

    def _resolve_name(self, node: ast.Name) -> str:
        """解析 ast.Name 节点"""
        id_map: dict[str, str] = {
            'str': 'i8*', 'int': 'i32', 'bool': 'i8',
            'float': 'double', 'None': 'void',
            'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*',
            'UINT16PTR': 'i16*', 'INT16PTR': 'i16*',
            'UINT32PTR': 'i32*', 'INT32PTR': 'i32*',
            'UINT64PTR': 'i64*', 'INT64PTR': 'i64*',
        }
        if node.id in id_map:
            return id_map[node.id]
        # 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
        builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
        if builtin_entry:
            TypeClass: type
            base_ptr: int
            TypeClass, base_ptr = builtin_entry
            base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass)
            if base_ptr > 0:
                if base_llvm == 'void':
                    return 'i8*'
                return base_llvm + '*' * base_ptr
            return base_llvm if base_llvm else 'i32'
        # 查找 SymbolTable 中的 typedef
        if node.id in self._symtab:
            entry: CTypeInfo = self._symtab[node.id]
            if entry and entry.IsTypedef:
                # 优先用 OriginalType 解析
                if entry.OriginalType:
                    if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
                        return 'i8*'
                    elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
                        # 用 CTypeRegistry 生成归一化 LLVM 字符串（void*→i8*），struct/enum 回退 ToString()
                        resolved: str = self._ctype_to_llvm_str(entry.OriginalType)
                        if resolved:
                            return resolved
                        return entry.OriginalType.ToString()
                    elif isinstance(entry.OriginalType, str):
                        # 字符串形式的 OriginalType（如 'CUnsignedInt *'）需转换为 LLVM 类型字符串
                        llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType)
                        if llvm_str:
                            return llvm_str
                # OriginalType 为空或字符串无法转换时，回退到 BaseType
                if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0):
                    resolved = self._ctype_to_llvm_str(entry)
                    if resolved:
                        return resolved
        self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}'，回退到 i32")
        return 'i32'

    def _resolve_attribute(self, node: ast.Attribute) -> str:
        """解析 ast.Attribute 节点"""
        attr_name: str = node.attr if hasattr(node, 'attr') else ''
        llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
        if llvm_str is not None:
            return llvm_str
        if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
            return ''
        if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
            return 'i8*'
        if attr_name == 'CVoidPtr':
            return 'i8*'
        if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
            return f'%struct.{attr_name}*'
        if attr_name and attr_name not in CTypeRegistry._name_to_class:
            return f'%struct.{attr_name}*'
        self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}'，回退到 i32")
        return 'i32'

    def _resolve_subscript(self, node: ast.Subscript) -> str:
        """解析 ast.Subscript 节点"""
        if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
            slice_node: ast.AST = node.slice
            elem_types: list[str] = []
            if isinstance(slice_node, ast.Tuple):
                elt: ast.AST
                for elt in slice_node.elts:
                    elem_types.append(self.get_llvm_type_str(elt))
            else:
                elem_types.append(self.get_llvm_type_str(slice_node))
            if elem_types:
                return '{ ' + ', '.join(elem_types) + ' }'
        if IsListAnnotation(node):
            slice_node: ast.AST = node.slice
            elem_type: str
            if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
                elem_type = self.get_llvm_type_str(slice_node.elts[0])
            else:
                elem_type = self.get_llvm_type_str(slice_node)
            return elem_type + '*'
        self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型，回退到 i32")
        return 'i32'

    def _resolve_bitor(self, node: ast.BinOp) -> str:
        """解析 ast.BinOp(BitOr) 节点"""
        left: str = self.get_llvm_type_str(node.left)
        right: str = self.get_llvm_type_str(node.right)
        if right and right.endswith('*'):
            return right
        if left and left.endswith('*'):
            return left
        if left and left not in ('i32', 'void', 'i64'):
            return left
        if right and right not in ('i32', 'void', 'i64'):
            return right
        return left if left else right

    def _resolve_call(self, node: ast.Call) -> str:
        """解析 ast.Call 节点"""
        if isinstance(node.func, ast.Attribute):
            if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id):
                return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
        self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型，回退到 i32")
        return 'i32'
