import t, c
from stdint import *
import string
import viperlib
import memhub
from linkedlist import GSListNode
from .__types import LLVMType, TypePrint


# ============================================================
# Value: SSA 值表示
#
# 表示一个 LLVM IR 值：SSA 临时值（%0/%result）或常量字面量（42/0）。
# 每个值有类型指针、名字、是否常量标志。
# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr（值池链表）
#
# 注意: 必须加 @t.NoVTable（理由见 __function.py 的 Line 注释）。
# ============================================================
@t.NoVTable
class Value(GSListNode[Value]):
    Ty: LLVMType | t.CPtr       # 值的类型
    Name: t.CChar | t.CPtr      # SSA 名（"%0"/"%result"）或常量文本（"42"/"1.5e+00"）
    IsConst: t.CInt             # 1=常量字面量, 0=SSA 临时值
    IntVal: t.CInt64T           # 整数常量值（当 IsConst=1 时使用）
    FloatVal: t.CDouble         # 浮点常量值（当 IsConst=1 且 Ty 为 Float 时使用）


# ============================================================
# 工厂函数
# ============================================================
# Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节
VALUE_SIZE: t.CDefine = 48

def new_value(pool: memhub.MemBuddy | t.CPtr) -> Value | t.CPtr:
    """从 mpool 分配一个零初始化的 Value"""
    ptr: Value | t.CPtr = pool.alloc(VALUE_SIZE)
    if ptr:
        string.memset(ptr, 0, VALUE_SIZE)
    return ptr


def ConstInt(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
             val: t.CInt64T, name: t.CChar | t.CPtr) -> Value | t.CPtr:
    """创建整数常量值

    参数:
        ty: 整数类型（Int1/Int8/Int32/Int64）
        val: 整数值
        name: 常量文本（如 "42"），由调用方提供
    """
    v: Value | t.CPtr = new_value(pool)
    if v is None: return None
    v.Ty = ty
    v.Name = name
    v.IsConst = 1
    v.IntVal = val
    return v


def ConstNull(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
              name: t.CChar | t.CPtr) -> Value | t.CPtr:
    """创建 null 指针常量"""
    v: Value | t.CPtr = new_value(pool)
    if v is None: return None
    v.Ty = ty
    v.Name = name
    v.IsConst = 1
    v.IntVal = 0
    return v


def ConstZero(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
    """创建 zeroinitializer 常量（零初始化聚合类型：结构体/数组）"""
    v: Value | t.CPtr = new_value(pool)
    if v is None: return None
    v.Ty = ty
    v.Name = "zeroinitializer"
    v.IsConst = 1
    v.IntVal = 0
    return v


def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
               val: t.CDouble) -> Value | t.CPtr:
    """创建浮点常量值

    参数:
        ty: 浮点类型（Half/Float/Double/FP128）
        val: 浮点数值
    名字自动格式化为 LLVM IR 科学计数法文本（如 "1.500000e+00"）。
    """
    v: Value | t.CPtr = new_value(pool)
    if v is None: return None
    v.Ty = ty
    v.IsConst = 1
    v.FloatVal = val
    v.IntVal = 0
    # 格式化名字: LLVM IR 使用 "%e" 科学计数法（6 位小数）
    name_buf: t.CChar | t.CPtr = pool.alloc(32)
    if name_buf is not None:
        viperlib.snprintf(name_buf, 32, "%e", val)
    v.Name = name_buf
    return v


def SSAValue(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
             name: t.CChar | t.CPtr) -> Value | t.CPtr:
    """创建 SSA 临时值

    参数:
        ty: 值类型
        name: SSA 名（如 "%0"/"%result"），由调用方提供
    """
    v: Value | t.CPtr = new_value(pool)
    if v is None: return None
    v.Ty = ty
    v.Name = name
    v.IsConst = 0
    v.IntVal = 0
    return v


# ============================================================
# ValuePrint: 将值序列化为 IR 文本
#
# 示例:
#   ConstInt(i32, 42, "42")  -> "i32 42"
#   SSAValue(i32, "%0")      -> "i32 %0"
# ============================================================
def ValuePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
               val: Value | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
    """将值 val 序列化为 IR 文本写入 buf

    格式: <type> <name>
    pool 用于复杂类型（Array/Struct/Func）递归打印时分配临时缓冲区。
    """
    if val is None or buf is None or size == 0:
        return
    # 先写类型
    TypePrint(buf, size, val.Ty, pool)
    # 追加空格
    pos: t.CSizeT = string.strlen(buf)
    if pos + 1 < size:
        buf[pos] = ' '
        buf[pos + 1] = '\0'
    # 追加名字
    if val.Name is not None:
        pos = string.strlen(buf)
        _append_str(buf, size, val.Name)


# ============================================================
# Value 字段访问器（供其他模块绕过 stub 类型限制使用）
#
# 跨模块编译时，使用方模块只有 Value 的 stub 类型（字段不足或偏移错误），
# 导致 TransPyC 静默跳过字段访问（不生成 GEP，不报错）。
# 这些访问器在拥有完整类型定义的本模块内执行，能正确访问所有字段。
# ============================================================
def value_get_ty(val: Value | t.CPtr) -> LLVMType | t.CPtr:
    """获取值的类型"""
    if val is None:
        return None
    return val.Ty


def value_get_next(val: Value | t.CPtr) -> Value | t.CPtr:
    """获取链表下一个值"""
    if val is None:
        return None
    return val.Next


def value_set_ty(val: Value | t.CPtr, ty: LLVMType | t.CPtr):
    """设置值的类型"""
    if val is None:
        return
    val.Ty = ty


def value_set_next(val: Value | t.CPtr, nxt: Value | t.CPtr):
    """设置链表下一个值"""
    if val is None:
        return
    val.Next = nxt


def value_set_name(val: Value | t.CPtr, name: t.CChar | t.CPtr):
    """设置值的名字"""
    if val is None:
        return
    val.Name = name


def value_set_isconst(val: Value | t.CPtr, is_const: t.CInt):
    """设置是否为常量"""
    if val is None:
        return
    val.IsConst = is_const


# ============================================================
# 内部辅助
# ============================================================
def _append_str(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
    """将 src 追加到 dst 末尾"""
    if dst is None or src is None: return
    dlen: t.CSizeT = string.strlen(dst)
    slen: t.CSizeT = string.strlen(src)
    remain: t.CSizeT = dst_size - dlen
    if remain <= 0: return
    i: t.CSizeT = 0
    while i < slen and i + 1 < remain:
        dst[dlen + i] = src[i]
        i += 1
    dst[dlen + i] = '\0'
