from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from lib.core.translator import Translator
import ast
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext


class IfHandle(BaseHandle):
    def _get_attr_full_name(self, node: ast.expr) -> str | None:
        if isinstance(node, ast.Attribute):
            parts: list[str] = []
            cur: ast.expr = node
            while isinstance(cur, ast.Attribute):
                parts.append(cur.attr)
                cur = cur.value
            if isinstance(cur, ast.Name):
                parts.append(cur.id)
            parts.reverse()
            return '.'.join(parts)
        return None

    def _is_cif_call(self, node: ast.expr) -> bool:
        if isinstance(node, ast.Call):
            if isinstance(node.func, ast.Attribute):
                if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c':
                    return node.func.attr in ('CIf', 'CIfdef', 'CIfndef')
            if isinstance(node.func, ast.Name):
                return node.func.id in ('CIf', 'CIfdef', 'CIfndef')
        return False

    def _resolve_macro_name(self, arg: ast.expr) -> str | None:
        if isinstance(arg, ast.Name):
            return arg.id
        if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
            return arg.value
        if isinstance(arg, ast.Attribute):
            full_name: str | None = self._get_attr_full_name(arg)
            if full_name:
                return full_name
        return None

    def _evaluate_cif_condition(self, node: ast.Call) -> int | None:
        if not isinstance(node, ast.Call):
            return None
        args: list[ast.expr] = node.args
        if not args:
            return 0
        kind: str | None = None
        if isinstance(node.func, ast.Attribute):
            kind = node.func.attr
        elif isinstance(node.func, ast.Name):
            kind = node.func.id
        else:
            return None
        if kind == 'CIfdef':
            name: str | None = self._resolve_macro_name(args[0])
            if name is None:
                return 0
            return 1 if self._is_macro_defined(name) else 0
        elif kind == 'CIfndef':
            name: str | None = self._resolve_macro_name(args[0])
            if name is None:
                return 1
            return 0 if self._is_macro_defined(name) else 1
        elif kind == 'CIf':
            return self._eval_const_expr(args[0])
        return None

    def _is_macro_defined(self, name: str) -> bool:
        Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
        if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
            return True
        if self.Trans.SymbolTable.is_define(name):
            return True
        platform_macros: dict[str, int] = self._get_platform_macros()
        return name in platform_macros

    def _get_macro_value(self, name: str) -> int | float | None:
        Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
        if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
            val: int | float | None = Gen._define_constants[name]
            if isinstance(val, (int, float)):
                return val
        info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
        if info:
            if info.IsDefine:
                val: int | float | None = info.DefineValue
                if isinstance(val, (int, float)):
                    return val
        platform_macros: dict[str, int] = self._get_platform_macros()
        if name in platform_macros:
            return platform_macros[name]
        return None

    def _get_platform_macros(self) -> dict[str, int]:
        Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
        macros: dict[str, int] = {}
        pi: dict[str, object] = Gen._platform_info
        ptr_size: int = getattr(Gen, 'ptr_size', 8)
        # 根据目标平台设置宏（从三元组推导）
        if pi.get('is_windows'):
            macros['_WIN32'] = 1
            if not pi.get('is_32bit'):
                macros['_WIN64'] = 1
                macros['WIN64'] = 1
            macros['WIN32'] = 1
        if pi.get('is_linux'):
            macros['__linux__'] = 1
        if pi.get('is_macos'):
            macros['__APPLE__'] = 1
            macros['__MACH__'] = 1
        if pi.get('is_x86_64'):
            macros['__x86_64__'] = 1
            macros['__x86_64'] = 1
            macros['_M_X64'] = 1
        elif pi.get('is_arm64'):
            macros['__aarch64__'] = 1
            macros['_M_ARM64'] = 1
        if not pi.get('is_32bit') and pi.get('is_linux'):
            macros['__LP64__'] = 1
        elif pi.get('is_32bit'):
            macros['_ILP32'] = 1
        macros['SIZEOF_VOID_P'] = ptr_size
        macros['__SIZEOF_POINTER__'] = ptr_size
        macros['NDEBUG'] = 0
        return macros

    def _eval_const_expr(self, node: ast.expr) -> int | None:
        Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
        ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans)
        result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx)
        if result is None:
            # 保留 CIf 嵌套调用处理（HandlesIf 特有逻辑）
            if isinstance(node, ast.Call) and self._is_cif_call(node):
                return self._evaluate_cif_condition(node)
            return None
        # HandlesIf 需要 bool/float → int 转换（#if 条件编译语义）
        if isinstance(result, bool):
            return 1 if result else 0
        if isinstance(result, float):
            return 1 if result != 0.0 else 0
        return result

    def _HandleIfLlvm(self, Node: ast.If) -> None:
        Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
        if self._is_cif_call(Node.test):
            compile_time_val: int | None = self._evaluate_cif_condition(Node.test)
            if compile_time_val is not None:
                if compile_time_val:
                    self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
                elif Node.orelse:
                    if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
                        self._HandleIfLlvm(Node.orelse[0])
                    else:
                        self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
                return
        Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test)
        if not Cond:
            return
        is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1
        if is_const:
            if Cond.constant:
                self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
            elif Node.orelse:
                if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If):
                    self._HandleIfLlvm(Node.orelse[0])
                else:
                    self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
            return
        if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
            ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen)
            if ClassName and Gen._has_function(f'{ClassName}.__bool__'):
                obj_val: ir.Value = Cond
                if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8:
                    obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
                Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__")
                if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1:
                    Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result")
            else:
                if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
                    Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond")
                else:
                    Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond")
        ThenBB: ir.Block = Gen.func.append_basic_block(name="then")
        ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None
        MergeBB: ir.Block = Gen.func.append_basic_block(name="endif")
        if not Gen.builder.block.is_terminated:
            Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB)
        Gen.builder.position_at_start(ThenBB)
        self.Trans.BodyHandler.HandleBodyLlvm(Node.body)
        if not Gen.builder.block.is_terminated:
            Gen.builder.branch(MergeBB)
        if ElseBB:
            Gen.builder.position_at_start(ElseBB)
            self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse)
            if not Gen.builder.block.is_terminated:
                Gen.builder.branch(MergeBB)
        if not MergeBB.is_terminated:
            Gen.builder.position_at_start(MergeBB)
        else:
            Gen.builder.position_at_end(MergeBB)