"""Tests for the implies / implied_by / implied_by_any / implied_by_all markers."""

import textwrap


def test_implies_implied_by_basic(pytester):
    """implied_by test is skipped (synthetic PASSED) when implier passes."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("strong_ok")
        def test_strong():
            assert True

        @pytest.mark.implied_by("strong_ok")
        def test_weak():
            # Should never execute
            raise RuntimeError("should not run")
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=2)
    assert "IMPLIED" in result.stdout.str()


def test_implied_by_runs_when_implier_fails(pytester):
    """When the implier fails, the implied test runs normally."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("strong_ok")
        def test_strong():
            assert False

        @pytest.mark.implied_by("strong_ok")
        def test_weak():
            assert True
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=1, failed=1)
    assert "IMPLIED" not in result.stdout.str()


def test_implied_by_runs_when_implier_not_collected(pytester):
    """When -k filters out the implier, implied tests run normally."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("strong_ok")
        def test_strong():
            assert True

        @pytest.mark.implied_by("strong_ok")
        def test_weak():
            assert True
    """))
    result = pytester.runpytest("-v", "-k", "weak")
    result.assert_outcomes(passed=1)
    assert "IMPLIED" not in result.stdout.str()


def test_implies_ordering(pytester):
    """Implier runs before implied regardless of file order."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        order = []

        @pytest.mark.implied_by("alpha_ok")
        def test_aaa():
            order.append("aaa")

        @pytest.mark.implies("alpha_ok")
        def test_zzz():
            order.append("zzz")

        def test_check():
            # zzz must run before aaa; aaa is implied so never runs
            assert order == ["zzz"]
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=3)


def test_implied_by_any_or_semantics(pytester):
    """implied_by_any: test is implied when ANY token passes (OR)."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("tok_a")
        def test_a():
            assert False   # fails — tok_a not recorded

        @pytest.mark.implies("tok_b")
        def test_b():
            assert True    # passes — tok_b recorded

        @pytest.mark.implied_by_any("tok_a", "tok_b")
        def test_needs_either():
            raise RuntimeError("should not run")
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=2, failed=1)
    assert "IMPLIED" in result.stdout.str()


def test_implied_by_all_and_semantics(pytester):
    """implied_by_all: test is implied only when ALL tokens pass (AND)."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("tok_a")
        def test_a():
            assert True

        @pytest.mark.implies("tok_b")
        def test_b():
            assert True

        @pytest.mark.implied_by_all("tok_a", "tok_b")
        def test_needs_both():
            raise RuntimeError("should not run")
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=3)
    assert "IMPLIED" in result.stdout.str()


def test_implied_by_all_not_satisfied(pytester):
    """implied_by_all: test runs when not all tokens are recorded."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        @pytest.mark.implies("tok_a")
        def test_a():
            assert False   # fails — tok_a not recorded

        @pytest.mark.implies("tok_b")
        def test_b():
            assert True    # passes — tok_b recorded

        @pytest.mark.implied_by_all("tok_a", "tok_b")
        def test_needs_both():
            assert True    # must run since tok_a missing
    """))
    result = pytester.runpytest("-v")
    result.assert_outcomes(passed=2, failed=1)
    assert "IMPLIED" not in result.stdout.str()


def test_no_imply_flag(pytester):
    """--no-imply forces all tests to run."""
    pytester.makepyfile(textwrap.dedent("""\
        import pytest

        ran = []

        @pytest.mark.implies("strong_ok")
        def test_strong():
            ran.append("strong")

        @pytest.mark.implied_by("strong_ok")
        def test_weak():
            ran.append("weak")

        def test_check():
            assert ran == ["strong", "weak"]
    """))
    result = pytester.runpytest("-v", "--no-imply")
    result.assert_outcomes(passed=3)
    assert "IMPLIED" not in result.stdout.str()
