"""ADR-0131.1 — tests for the symbolic equivalence check primitive."""

from __future__ import annotations

from generate.math_symbolic_equivalence import (
    Verdict,
    check_equivalence,
)


class TestEquivalent:
    def test_identical_expressions(self) -> None:
        v = check_equivalence("x + 1", "x + 1")
        assert v.verdict == Verdict.EQUIVALENT
        assert v.canonical_a == v.canonical_b == "x+1"

    def test_distributive(self) -> None:
        v = check_equivalence("2*(x + 3)", "2*x + 6")
        assert v.verdict == Verdict.EQUIVALENT

    def test_square_of_binomial(self) -> None:
        v = check_equivalence("(x + 1)^2", "x^2 + 2*x + 1")
        assert v.verdict == Verdict.EQUIVALENT

    def test_difference_of_squares(self) -> None:
        v = check_equivalence("(x + 1)*(x - 1)", "x^2 - 1")
        assert v.verdict == Verdict.EQUIVALENT

    def test_collect_like_terms(self) -> None:
        v = check_equivalence("2*x + 3*x + x", "6*x")
        assert v.verdict == Verdict.EQUIVALENT

    def test_zero_cancellation(self) -> None:
        v = check_equivalence("x - x + 5", "5")
        assert v.verdict == Verdict.EQUIVALENT


class TestNotEquivalent:
    def test_different_constant(self) -> None:
        v = check_equivalence("x + 1", "x + 2")
        assert v.verdict == Verdict.NOT_EQUIVALENT
        assert v.canonical_a == "x+1"
        assert v.canonical_b == "x+2"

    def test_different_degree(self) -> None:
        v = check_equivalence("x^2", "x^3")
        assert v.verdict == Verdict.NOT_EQUIVALENT

    def test_sign_flipped(self) -> None:
        v = check_equivalence("(x + 1)^2", "(x - 1)^2")
        assert v.verdict == Verdict.NOT_EQUIVALENT


class TestRefused:
    def test_empty_left(self) -> None:
        v = check_equivalence("", "x + 1")
        assert v.verdict == Verdict.REFUSED
        assert "empty" in v.reason

    def test_multivariable_now_admits(self) -> None:
        # ADR-0131.1.B scope expansion: multivariable polynomials are admissible.
        v = check_equivalence("x + y", "x + 1")
        assert v.verdict == Verdict.NOT_EQUIVALENT

    def test_constant_denominator_now_admits(self) -> None:
        # ADR-0131.1.B scope expansion: constant-denominator division admits.
        v = check_equivalence("x/2", "x")
        assert v.verdict == Verdict.NOT_EQUIVALENT

    def test_symbolic_denominator_still_refused(self) -> None:
        # Symbolic-denominator division stays out of scope.
        v = check_equivalence("x/y", "x")
        assert v.verdict == Verdict.REFUSED

    def test_a_normalizes_b_refuses(self) -> None:
        # a is fine, b uses a transcendental -> refusal.
        v = check_equivalence("x + 1", "sin(x)")
        assert v.verdict == Verdict.REFUSED
        assert v.canonical_b is None

    def test_refused_verdict_is_first_class(self) -> None:
        # Refusal preserves wrong == 0 — the verdict is REFUSED, never
        # silently coerced to NOT_EQUIVALENT.
        v = check_equivalence("garbage(", "x")
        assert v.verdict == Verdict.REFUSED


class TestDeterminism:
    def test_same_inputs_same_verdict(self) -> None:
        # Re-running produces byte-equal verdict.
        a, b = "(x + 2)*(x - 2)", "x^2 - 4"
        v1 = check_equivalence(a, b)
        v2 = check_equivalence(a, b)
        assert v1 == v2

    def test_canonical_strings_are_byte_equal_on_equivalence(self) -> None:
        v = check_equivalence("(x + 1)^2", "x^2 + 2*x + 1")
        assert v.canonical_a is not None
        assert v.canonical_b is not None
        assert v.canonical_a.encode("utf-8") == v.canonical_b.encode("utf-8")
