import t
import stdio
import string
import testcheck
import linkedlist
import viperlib
import stdlib


# ============================================================
# 子类继承 linkedlist.LinkedNode：启用链表/树形能力
# 字段展平，无 vtable；OOP 方法通过 _generate_inherited_method_wrappers
# 自动生成子类包装（self bitcast 为父类指针后调用父类方法）。
# 从 LinkedNode* 取回 Node* 需显式向下转型：(Node | t.CPtr)(ptr)
# ============================================================
class Node(linkedlist.LinkedNode):
    value: t.CInt


# ============================================================
# 测试 1：append + child_count
# ============================================================
def test_append():
    testcheck.section("Test 1: append")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    c: Node = Node()
    a.value = 10
    b.value = 20
    c.value = 30
    root.append(a)
    root.append(b)
    root.append(c)
    testcheck.check(root.child_count == 3,
                    "append count=3",
                    "append count fail")
    # 验证顺序（LinkedNode* → Node* 显式向下转型）
    c1: Node | t.CPtr = (Node | t.CPtr)(root.child)
    c2: Node | t.CPtr = (Node | t.CPtr)(c1.next)
    c3: Node | t.CPtr = (Node | t.CPtr)(c2.next)
    testcheck.check(c1.value == 10 and c2.value == 20 and c3.value == 30,
                    "order 10,20,30",
                    "order fail")


# ============================================================
# 测试 2：双向链表 prev 指针
# ============================================================
def test_prev_link():
    testcheck.section("Test 2: prev pointer (doubly linked)")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    a.value = 1
    b.value = 2
    root.append(a)
    root.append(b)
    # b.prev 应指向 a
    bp: Node | t.CPtr = (Node | t.CPtr)(b.prev)
    testcheck.check(bp is not None and bp.value == 1,
                    "b.prev.value=1",
                    "prev link fail")
    # a.prev 应为 None（第一个子节点）
    testcheck.check(a.prev is None,
                    "a.prev=None",
                    "first prev fail")


# ============================================================
# 测试 3：last_child 指针（O(1) 追加验证）
# ============================================================
def test_last_child():
    testcheck.section("Test 3: last_child pointer")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    a.value = 100
    b.value = 200
    root.append(a)
    lc: Node | t.CPtr = (Node | t.CPtr)(root.last_child)
    testcheck.check(lc is not None and lc.value == 100,
                    "last_child=100 after 1 append",
                    "last_child fail 1")
    root.append(b)
    lc = (Node | t.CPtr)(root.last_child)
    testcheck.check(lc is not None and lc.value == 200,
                    "last_child=200 after 2 append",
                    "last_child fail 2")


# ============================================================
# 测试 4：detach（O(1) 摘除）
# ============================================================
def test_remove():
    testcheck.section("Test 4: detach (O(1) unlink)")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    c: Node = Node()
    a.value = 1
    b.value = 2
    c.value = 3
    root.append(a)
    root.append(b)
    root.append(c)
    # 摘除中间的 b
    b.detach()
    testcheck.check(root.child_count == 2,
                    "count=2 after detach",
                    "detach count fail")
    # a.next 应直接指向 c
    an: Node | t.CPtr = (Node | t.CPtr)(a.next)
    testcheck.check(an is not None and an.value == 3,
                    "a.next.value=3",
                    "detach link fail")
    # c.prev 应指向 a
    cp: Node | t.CPtr = (Node | t.CPtr)(c.prev)
    testcheck.check(cp is not None and cp.value == 1,
                    "c.prev.value=1",
                    "detach prev fail")
    # b 的链接应清空
    testcheck.check(b.parent is None and b.next is None and b.prev is None,
                    "b cleared",
                    "b not cleared")


# ============================================================
# 测试 5：remove_child
# ============================================================
def test_remove_child():
    testcheck.section("Test 5: remove_child")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    a.value = 10
    b.value = 20
    root.append(a)
    root.append(b)
    root.remove_child(a)
    testcheck.check(root.child_count == 1,
                    "count=1 after remove_child",
                    "remove_child count fail")
    fc: Node | t.CPtr = (Node | t.CPtr)(root.child)
    testcheck.check(fc is not None and fc.value == 20,
                    "first child=20",
                    "remove_child first fail")


# ============================================================
# 测试 6：prepend + insert_before + insert_after
# ============================================================
def test_insert_ops():
    testcheck.section("Test 6: prepend/insert_before/insert_after")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    c: Node = Node()
    d: Node = Node()
    a.value = 1
    b.value = 2
    c.value = 3
    d.value = 4
    root.append(a)       # [1]
    root.append(c)       # [1, 3]
    root.insert_before(c, b)   # [1, 2, 3]  在 c 前插入 b
    root.insert_after(a, d)    # [1, 4, 2, 3] 在 a 后插入 d
    # 遍历验证顺序
    cur: Node | t.CPtr = (Node | t.CPtr)(root.child)
    v0: t.CInt = cur.value
    cur = (Node | t.CPtr)(cur.next)
    v1: t.CInt = cur.value
    cur = (Node | t.CPtr)(cur.next)
    v2: t.CInt = cur.value
    cur = (Node | t.CPtr)(cur.next)
    v3: t.CInt = cur.value
    testcheck.check(v0 == 1 and v1 == 4 and v2 == 2 and v3 == 3,
                    "order 1,4,2,3",
                    "insert order fail")
    testcheck.check(root.child_count == 4,
                    "count=4",
                    "insert count fail")


# ============================================================
# 测试 7：child_at + count_children
# 注意：Viper 中 Node() 是栈分配，循环内 n 会被复用（同一地址），
# 导致所有子节点指向同一内存。必须用独立变量保证各节点地址不同。
# ============================================================
def test_index_access():
    testcheck.section("Test 7: child_at + count_children")
    root: Node = Node()
    n0: Node = Node()
    n1: Node = Node()
    n2: Node = Node()
    n3: Node = Node()
    n4: Node = Node()
    n0.value = 0
    n1.value = 10
    n2.value = 20
    n3.value = 30
    n4.value = 40
    root.append(n0)
    root.append(n1)
    root.append(n2)
    root.append(n3)
    root.append(n4)
    # child_at
    r0: Node | t.CPtr = (Node | t.CPtr)(root.child_at(0))
    r2: Node | t.CPtr = (Node | t.CPtr)(root.child_at(2))
    r4: Node | t.CPtr = (Node | t.CPtr)(root.child_at(4))
    r5: Node | t.CPtr = (Node | t.CPtr)(root.child_at(5))
    testcheck.check(r0 is not None and r0.value == 0,
                    "child_at(0)=0",
                    "child_at 0 fail")
    testcheck.check(r2 is not None and r2.value == 20,
                    "child_at(2)=20",
                    "child_at 2 fail")
    testcheck.check(r4 is not None and r4.value == 40,
                    "child_at(4)=40",
                    "child_at 4 fail")
    testcheck.check(r5 is None,
                    "child_at(5)=None",
                    "child_at 5 fail")
    # count_children
    cc: t.CSizeT = root.count_children()
    testcheck.check(cc == 5,
                    "count_children=5",
                    "count_children fail")


# ============================================================
# 测试 8：has_children + first_sibling/last_sibling
# ============================================================
def test_sibling_traverse():
    testcheck.section("Test 8: has_children + sibling traverse")
    root: Node = Node()
    testcheck.check(root.has_children() == 0,
                    "empty has_children=0",
                    "has_children empty fail")
    a: Node = Node()
    b: Node = Node()
    c: Node = Node()
    a.value = 1
    b.value = 2
    c.value = 3
    root.append(a)
    root.append(b)
    root.append(c)
    testcheck.check(root.has_children() == 1,
                    "has_children=1",
                    "has_children fail")
    # 从 b 出发找头尾兄弟
    fs: Node | t.CPtr = (Node | t.CPtr)(b.first_sibling())
    ls: Node | t.CPtr = (Node | t.CPtr)(b.last_sibling())
    testcheck.check(fs is not None and fs.value == 1,
                    "first_sibling=1",
                    "first_sibling fail")
    testcheck.check(ls is not None and ls.value == 3,
                    "last_sibling=3",
                    "last_sibling fail")


# ============================================================
# 测试 9：unlink（断开所有连接）
# ============================================================
def test_unlink():
    testcheck.section("Test 9: unlink")
    root: Node = Node()
    a: Node = Node()
    b: Node = Node()
    a.value = 1
    b.value = 2
    root.append(a)
    root.append(b)
    # unlink a：从兄弟链摘除 + 断开父子链接
    a.unlink()
    testcheck.check(a.next is None and a.prev is None and a.parent is None,
                    "a links cleared",
                    "a links not cleared")
    testcheck.check(a.child is None and a.last_child is None and a.child_count == 0,
                    "a child cleared",
                    "a child not cleared")
    # root 应只剩 b
    testcheck.check(root.child_count == 1,
                    "root count=1 after unlink",
                    "root count fail")


# ============================================================
# 测试 10：SListNode 单向链表（OOP 方法）
# ============================================================
class SNode(linkedlist.SListNode):
    value: t.CInt


def test_slist():
    testcheck.section("Test 10: SListNode (singly linked, OOP)")
    n0: SNode = SNode()
    n1: SNode = SNode()
    n2: SNode = SNode()
    n0.value = 100
    n1.value = 200
    n2.value = 300
    # append (O(n)) — 直接用 n0 作为 head
    head: linkedlist.SListNode | t.CPtr = n0
    head = head.append(n1)
    head = head.append(n2)
    # count
    testcheck.check(head.count() == 3,
                    "count=3",
                    "count fail")
    # at
    a0: SNode | t.CPtr = (SNode | t.CPtr)(head.at(0))
    a1: SNode | t.CPtr = (SNode | t.CPtr)(head.at(1))
    a2: SNode | t.CPtr = (SNode | t.CPtr)(head.at(2))
    a3: SNode | t.CPtr = (SNode | t.CPtr)(head.at(3))
    testcheck.check(a0 is not None and a0.value == 100,
                    "at(0)=100",
                    "at 0 fail")
    testcheck.check(a1 is not None and a1.value == 200,
                    "at(1)=200",
                    "at 1 fail")
    testcheck.check(a2 is not None and a2.value == 300,
                    "at(2)=300",
                    "at 2 fail")
    testcheck.check(a3 is None,
                    "at(3)=None",
                    "at 3 fail")
    # remove (移除中间节点 n1)
    head = head.remove(n1)
    testcheck.check(head.count() == 2,
                    "after remove count=2",
                    "remove count fail")
    testcheck.check(n1.Next is None,
                    "n1.Next cleared",
                    "n1.Next not cleared")
    # 移除后 a0.Next 应指向 n2
    a0b: SNode | t.CPtr = (SNode | t.CPtr)(a0.Next)
    testcheck.check(a0b is not None and a0b.value == 300,
                    "after remove a0.Next=300",
                    "a0.Next fail")
    # append_after (O(1))
    n3: SNode = SNode()
    n3.value = 400
    tail: linkedlist.SListNode | t.CPtr = n2.append_after(n3)
    testcheck.check(tail is n3,
                    "append_after returns n3",
                    "append_after fail")
    testcheck.check(head.count() == 3,
                    "after append count=3",
                    "append count fail")


# ============================================================
# 测试 11：viperlib.sprintf *args 转发
# ============================================================
def test_sprintf_vararg():
    testcheck.section("Test 11: viperlib.sprintf *args forwarding")
    # 测试 %d 单参数
    buf: t.CChar | t.CPtr = stdlib.malloc(32)
    if buf is None: return
    buf[0] = 0
    viperlib.sprintf(buf, "key%d", 42)
    testcheck.check(string.strcmp(buf, "key42") == 0,
                    "sprintf key42",
                    "sprintf key%d fail")
    # 测试无参数
    buf2: t.CChar | t.CPtr = stdlib.malloc(32)
    if buf2 is None: return
    buf2[0] = 0
    viperlib.sprintf(buf2, "hello")
    testcheck.check(string.strcmp(buf2, "hello") == 0,
                    "sprintf hello",
                    "sprintf no-arg fail")
    # 测试多参数
    buf3: t.CChar | t.CPtr = stdlib.malloc(32)
    if buf3 is None: return
    buf3[0] = 0
    viperlib.sprintf(buf3, "%d+%d=%d", 1, 2, 3)
    testcheck.check(string.strcmp(buf3, "1+2=3") == 0,
                    "sprintf 1+2=3",
                    "sprintf multi-arg fail")


# ============================================================
# 测试 12：泛型 GSListNode[T] + GSList[T]
#
# 验证 4 个技术点（为 llvmlite 简化铺路）：
#   1. 递归泛型 class GNode(GSListNode[GNode]):
#   2. @t.NoVTable + 泛型组合（GNode 无 vptr，字段展平）
#   3. 泛型类作字段类型 lst: GSList[GNode]
#   4. 泛型方法继承 lst.append(n) / lst.count() / lst.at(i)
#      （GSList[T] 的方法在特化 GSList[GNode] 后可用）
#
# 注：编译器暂不支持 模块.泛型类[T]() 跨模块构造，故本地定义。
# ============================================================
@t.NoVTable
class GSListNode[T]:
    Next: T | t.CPtr


@t.NoVTable
class GSList[T]:
    Head: T | t.CPtr
    Tail: T | t.CPtr
    Count: t.CSizeT

    def __init__(self):
        self.Head = None
        self.Tail = None
        self.Count = 0

    def append(self, node: T):
        if node is None: return
        node.Next = None
        if self.Head is None:
            self.Head = node
        else:
            self.Tail.Next = node
        self.Tail = node
        self.Count += 1

    def count(self) -> t.CSizeT:
        return self.Count

    def at(self, index: t.CSizeT) -> T | t.CPtr:
        if self.Head is None: return None
        cur: T | t.CPtr = self.Head
        i: t.CSizeT = 0
        while cur is not None:
            if i == index: return cur
            i += 1
            cur = cur.Next
        return None


class GNode(GSListNode[GNode]):
    Value: t.CInt


def test_generic_slist():
    testcheck.section("Test 12: Generic GSListNode[T] + GSList[T]")
    # 技术点 3: 泛型类作字段类型 + 构造
    lst: GSList[GNode] | t.CPtr = GSList[GNode]()

    # 技术点 1+2: 递归泛型 + NoVTable 组合（GNode 定义在上方）
    n0: GNode = GNode()
    n1: GNode = GNode()
    n2: GNode = GNode()
    n0.Value = 10
    n1.Value = 20
    n2.Value = 30

    # 技术点 4: 泛型方法继承
    lst.append(n0)
    lst.append(n1)
    lst.append(n2)

    # count (O(1))
    testcheck.check(lst.count() == 3,
                    "GSList.count()=3",
                    "GSList count fail")

    # at (O(n)) — 返回 GNode|CPtr，无需向下转型
    a0: GNode | t.CPtr = lst.at(0)
    a1: GNode | t.CPtr = lst.at(1)
    a2: GNode | t.CPtr = lst.at(2)
    a3: GNode | t.CPtr = lst.at(3)
    testcheck.check(a0 is not None and a0.Value == 10,
                    "GSList.at(0)=10",
                    "GSList at 0 fail")
    testcheck.check(a1 is not None and a1.Value == 20,
                    "GSList.at(1)=20",
                    "GSList at 1 fail")
    testcheck.check(a2 is not None and a2.Value == 30,
                    "GSList.at(2)=30",
                    "GSList at 2 fail")
    testcheck.check(a3 is None,
                    "GSList.at(3)=None",
                    "GSList at 3 fail")

    # Next 字段强类型（a0.Next 直接是 GNode|CPtr，无需转型）
    testcheck.check(a0.Next is a1,
                    "a0.Next is a1 (strong type)",
                    "a0.Next fail")
    testcheck.check(a1.Next is a2,
                    "a1.Next is a2 (strong type)",
                    "a1.Next fail")
    testcheck.check(a2.Next is None,
                    "a2.Next is None",
                    "a2.Next fail")


def main() -> t.CInt:
    testcheck.begin("NoVTableTest: linkedlist 库（@t.NoVTable OOP 方法 + 字段展平继承）")
    test_append()
    test_prev_link()
    test_last_child()
    test_remove()
    test_remove_child()
    test_insert_ops()
    test_index_access()
    test_sibling_traverse()
    test_unlink()
    test_slist()
    test_sprintf_vararg()
    test_generic_slist()
    return testcheck.end()
