import z3

from common.axioms import semi_linear_strict_order
from common.relations import relation

from . import Node, left, prec, right

c = z3.Const("c", Node)
P = relation("P", Node)


def preceq(x: z3.ExprRef, y: z3.ExprRef) -> z3.BoolRef:
    return z3.Or(x == y, prec(x, y))


def rogue_tree() -> z3.BoolRef:
    x, y = z3.Consts("x y", Node)
    return z3.And(
        semi_linear_strict_order(prec),
        z3.ForAll(x, prec(x, left(x))),
        z3.ForAll(x, prec(x, right(x))),
        z3.ForAll(x, left(x) != right(x)),
        z3.ForAll(
            [x, y],
            z3.Implies(prec(x, y), z3.Or(preceq(left(x), y), preceq(right(x), y))),
        ),
        z3.ForAll(x, z3.Implies(P(x), z3.And(P(left(x)), P(right(x))))),
        P(c),
        z3.ForAll(x, preceq(c, x)),
        z3.Exists(x, z3.Not(P(x))),
    )
