import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall


# ============================================================
# HandlesAnnAssign - AnnAssign 语句处理（Mixin 继承模式）
# ============================================================


# ============================================================
# is_cdefine_annotation - 检测注解是否为 t.CDefine（模块级函数）
#
# 支持两种形式:
#   1. Attribute(Name('t'), 'CDefine')
#   2. BinOp(... | Attribute(Name('t'), 'CDefine'))（联合注解）
# ============================================================
def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
    """检测注解是否为 t.CDefine，返回 1 表示是，0 表示否"""
    if annot is None:
        return 0
    k: int = annot.kind()
    if k == ast.ASTKind.Attribute:
        at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
        if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
            return 1
        return 0
    if k == ast.ASTKind.BinOp:
        bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
        if is_cdefine_annotation(bop.left) != 0:
            return 1
        if is_cdefine_annotation(bop.right) != 0:
            return 1
    return 0


# ============================================================
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量（模块级函数）
#
# 仅支持 ast.Constant(INT)，其他形式返回 0
# ============================================================
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
    """从值节点提取整数常量（仅支持 Constant INT）"""
    if val_node is None:
        return 0
    if val_node.kind() != ast.ASTKind.Constant:
        return 0
    cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
    if cn.const_kind != ast.CONST_INT:
        return 0
    return cn.int_val


@t.NoVTable
class AnnAssignHandle(HandlesBase.Mixin):
    """AnnAssign 语句处理器：继承 Mixin 获得 Trans 回指针"""

    def __init__(self, trans: HT.Translator | t.CPtr):
        self.Trans = trans

    # ============================================================
    # PreScan - 预扫描 AnnAssign，为有类型注解的变量提前创建 alloca
    #
    # 返回新增的变量数
    # ============================================================
    def PreScan(self, node: ast.AST | t.CPtr) -> int:
        """预扫描 AnnAssign，提前创建 alloca 到 entry block 顶部"""
        if node is None:
            return 0
        k: int = node.kind()
        if k != ast.ASTKind.AnnAssign:
            return 0

        aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
        if aa is None or aa.target is None:
            return 0
        target: ast.AST | t.CPtr = aa.target
        if target.kind() != ast.ASTKind.Name:
            return 0

        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
        if nm.id is None:
            return 0

        # CDefine 注解: 不创建 alloca，但注册常量到全局表
        # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用
        if is_cdefine_annotation(aa.annotation) != 0:
            pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool
            val_ps: int = extract_cdefine_int_value(aa.value)
            HandlesType.register_cdefine_constant(pool_ps, nm.id, val_ps)
            return 0

        # global/nonlocal 变量不需要局部 alloca
        if HT.is_global_name(self.Trans, nm.id) != 0:
            return 0
        if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
            return 0

        # 检查是否已存在
        existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
            self.Trans.SymTab, nm.id)
        if existing is not None:
            return 0

        pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
        builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder

        # 从 annotation 推断类型（修复：原硬编码 i32 导致 str 等类型错误）
        var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
        annot: ast.AST | t.CPtr = aa.annotation
        if annot is not None:
            resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
            if resolved is None:
                # 尝试特化泛型类注解（如 list[str]）
                # resolve_annotation_type 返回 None 可能是因为泛型类未特化
                if annot.kind() == ast.ASTKind.Subscript:
                    sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
                    if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name:
                        sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value)
                        if sub_nm.id is not None:
                            template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id)
                            if template_cd is not None:
                                type_args_ps: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_annot.slice)
                                if type_args_ps is not None and type_args_ps.__len__() > 0:
                                    spec_name_ps: str = HandlesClassDef._specialize_generic_class(
                                        self.Trans, sub_nm.id, type_args_ps)
                                    if spec_name_ps is not None:
                                        resolved = HandlesType.resolve_annotation_type(
                                            pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
            if resolved is not None:
                var_ty = resolved

        alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, var_ty)
        if alloca is not None:
            if HandlesVar.define_var(
                    self.Trans.SymTab, nm.id, alloca) == 0:
                # 存储原始类型注解的类名（方法调用检测时，Ptr(i8) 回退到类名查找结构体）
                if annot is not None:
                    cls_nm_ps: str = HandlesType.extract_class_name_from_annotation(
                        annot, self.Trans._imported_modules)
                    if cls_nm_ps is not None:
                        HandlesVar.set_var_annot_class_name(
                            self.Trans.SymTab, nm.id, cls_nm_ps)
                return 0
        return 0

    # ============================================================
    # Handle - 翻译 AnnAssign 语句
    #
    # 返回新增的变量数
    # ============================================================
    def Handle(self, node: ast.AST | t.CPtr) -> int:
        """翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
        aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
        if aa is None:
            return 0

        target: ast.AST | t.CPtr = aa.target
        if target is None or target.kind() != ast.ASTKind.Name:
            return 0

        nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
        if nm.id is None:
            return 0

        # CDefine 注解: 编译期常量，不生成运行时代码
        # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
        # 注: PreScan 已注册过，此处保证即使跳过 PreScan 也能正确注册
        if is_cdefine_annotation(aa.annotation) != 0:
            pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool
            val_cd: int = extract_cdefine_int_value(aa.value)
            HandlesType.register_cdefine_constant(pool_cd, nm.id, val_cd)
            return 0

        pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
        builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
        mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module

        # 确定类型（从 annotation 推断）
        var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
        annot: ast.AST | t.CPtr = aa.annotation
        if annot is not None:
            resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
                pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
            if resolved is not None:
                var_ty = resolved

        # global 变量：写入模块作用域中的全局变量
        if HT.is_global_name(self.Trans, nm.id) != 0:
            mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
                self.Trans.SymTab, nm.id)
            if mod_alloca is not None and aa.value is not None:
                rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
                    builder, pool, mod, aa.value,
                    None, 0, self.Trans)
                if rhs_val is not None:
                    target_ty: llvmlite.LLVMType | t.CPtr = None
                    if mod_alloca.Ty is not None:
                        target_ty = mod_alloca.Ty.Pointee
                    if target_ty is not None:
                        rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
                    llvmlite.build_store(builder, rhs_val, mod_alloca)
            return 0

        # nonlocal 变量：通过闭包 env 写入
        if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
            if aa.value is not None:
                rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
                    builder, pool, mod, aa.value,
                    None, 0, self.Trans)
                if rhs_val is not None:
                    nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
                        self.Trans, nm.id)
                    if nl_ptr is not None:
                        i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
                        rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
                            builder, rhs_val, i32_ty)
                        llvmlite.build_store(builder, rhs_coerced, nl_ptr)
            return 0

        # 普通局部变量
        # 创建 alloca
        alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
            self.Trans.SymTab, pool, builder, nm.id, var_ty)
        if alloca is None:
            return 0
        # 存储原始类型注解的类名（方法调用检测时，Ptr(i8) 回退到类名查找结构体）
        if annot is not None:
            cls_nm_hd: str = HandlesType.extract_class_name_from_annotation(
                annot, self.Trans._imported_modules)
            if cls_nm_hd is not None:
                HandlesVar.set_var_annot_class_name(
                    self.Trans.SymTab, nm.id, cls_nm_hd)

        new_vars: int = 0
        existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
            self.Trans.SymTab, nm.id)
        if existing is None:
            new_vars = 1

        # 如果有初始值，store
        if aa.value is not None:
            rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
                builder, pool, mod, aa.value,
                None, 0, self.Trans)
            if rhs_val is not None:
                # 类型转换：将 rhs_val 转换为 alloca 的 pointee 类型
                # 修复：整数字面量是 i32，但变量可能是 i8/i16/i64，需 trunc/sext
                target_ty: llvmlite.LLVMType | t.CPtr = None
                if alloca.Ty is not None:
                    target_ty = alloca.Ty.Pointee
                if target_ty is not None:
                    rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
                llvmlite.build_store(builder, rhs_val, alloca)

        return 0


# ============================================================
# NewAnnAssignHandle - 工厂函数
# ============================================================
def NewAnnAssignHandle(pool: memhub.MemBuddy | t.CPtr,
                       trans: HT.Translator | t.CPtr) -> AnnAssignHandle | t.CPtr:
    h: AnnAssignHandle | t.CPtr = pool.alloc(AnnAssignHandle.__sizeof__())
    if h is None:
        return None
    string.memset(h, 0, AnnAssignHandle.__sizeof__())
    h.Trans = trans
    return h
