"""Harness coverage for the custom JUnit properties.

No proxy and no ``e2e`` marker. Pins the two normalizations that have to agree
about where a suite file lives -- ``package_from_nodeid`` (strip the suite root)
and ``source_from_location`` (re-root at it) -- across both ways the suite is
launched, plus the one-based line offset and the refusal to emit a path that
escapes the suite. The consumers of these properties are the Loki/Grafana
rollups and, for ``source``, the status page's per-test links to GitHub.
"""

from __future__ import annotations

from pathlib import Path

import pytest
from junit_properties import (
    SUITE_ROOT,
    attach_result_properties,
    dedupe_covers,
    package_from_nodeid,
    result_properties,
    source_from_location,
    suite_parts,
)


def collected_item(request: pytest.FixtureRequest, name: str) -> pytest.Item:
    """The Item pytest collected for test ``name`` in this file: the real nodeid,
    location and marker machinery the collection hook reads, as pytest built it."""
    return next(item for item in request.session.items if item.path == request.path and item.name == name)


def repo_root() -> Path | None:
    """The litellm checkout above this file, or None when there isn't one."""
    return next((p for p in Path(__file__).resolve().parents if (p / ".git").exists()), None)


class TestSuiteParts:
    @pytest.mark.parametrize(
        "path",
        ["logging/test_x.py", "tests/e2e/logging/test_x.py", "./logging/test_x.py", "tests\\e2e\\logging\\test_x.py"],
    )
    def test_both_invocation_shapes_collapse_to_the_same_components(self, path: str) -> None:
        """A repo-root run and a suite-cwd run report the same file differently;
        every downstream signal has to see one spelling."""
        assert suite_parts(path) == ("logging", "test_x.py")

    def test_top_level_suite_file_keeps_its_single_component(self) -> None:
        assert suite_parts("tests/e2e/test_fixture_mode.py") == ("test_fixture_mode.py",)


class TestPackageFromNodeid:
    @pytest.mark.parametrize(
        ("nodeid", "expected"),
        [
            ("logging/test_x.py::TestFoo::test_bar", "logging"),
            ("tests/e2e/logging/test_x.py::TestFoo::test_bar", "logging"),
            ("quota_management/spend_tracking/test_x.py::test_bar", "quota_management"),
            ("test_fixture_mode.py::TestParseFixtureMode::test_known_values_normalize", "root"),
            ("tests/e2e/test_fixture_mode.py::test_bar", "root"),
        ],
    )
    def test_package_is_the_first_dir_under_the_suite_root(self, nodeid: str, expected: str) -> None:
        assert package_from_nodeid(nodeid) == expected


class TestSourceFromLocation:
    @pytest.mark.parametrize("path", ["a2a/test_a2a_agent_e2e.py", "tests/e2e/a2a/test_a2a_agent_e2e.py"])
    def test_path_is_repo_relative_however_pytest_was_started(self, path: str) -> None:
        assert source_from_location(path, 40) == "tests/e2e/a2a/test_a2a_agent_e2e.py:41"

    def test_line_is_emitted_one_based(self) -> None:
        """pytest.Item.location counts from 0; editors, tracebacks and GitHub's
        #L anchor all count from 1, and an off-by-one lands on the decorator."""
        assert source_from_location("a2a/test_x.py", 0) == "tests/e2e/a2a/test_x.py:1"

    def test_top_level_suite_file_sits_directly_under_the_suite_root(self) -> None:
        assert source_from_location("test_fixture_mode.py", 39) == "tests/e2e/test_fixture_mode.py:40"

    @pytest.mark.parametrize(
        ("path", "lineno"),
        [
            ("a2a/test_x.py", None),
            ("/app/e2e/a2a/test_x.py", 40),
            ("C:\\app\\e2e\\a2a\\test_x.py", 40),
            ("../conftest.py", 40),
            ("", 40),
        ],
    )
    def test_nothing_linkable_yields_empty_rather_than_a_guess(self, path: str, lineno: int | None) -> None:
        """A colon is rejected on two counts: it is how a Windows absolute path
        arrives, and `path:line` cannot represent one in the path half."""
        assert source_from_location(path, lineno) == ""


class TestResultProperties:
    def test_every_test_carries_package_covers_and_source(self, request: pytest.FixtureRequest) -> None:
        """Read off this test's own collected Item, so the nodeid and location are
        whatever pytest reports for the launch shape in use, and the marker is added
        at run time so the coverage registry's collect-only pass never sees it."""
        test = type(self).test_every_test_carries_package_covers_and_source
        request.applymarker(pytest.mark.covers("LOG-1", "LOG-2"))
        assert result_properties(collected_item(request, test.__name__)) == (
            ("package", "root"),
            ("covers", "LOG-1,LOG-2"),
            ("source", f"tests/e2e/test_junit_properties.py:{test.__code__.co_firstlineno}"),
        )

    def test_attach_is_idempotent(self, request: pytest.FixtureRequest) -> None:
        """Collection can run the hook more than once; a second pass must not
        double the <property> entries in the report."""
        item = collected_item(request, type(self).test_attach_is_idempotent.__name__)
        attach_result_properties(item)
        attach_result_properties(item)
        assert [name for name, _ in item.user_properties] == ["package", "covers", "source"]


class TestSuiteRoot:
    def test_suite_root_names_this_file_s_real_home(self) -> None:
        """SUITE_ROOT is hardcoded because the runner image has no repo to read it
        from. Where there IS a checkout, prove the constant still points at us --
        otherwise a moved tests/e2e/ ships links that 404."""
        root = repo_root()
        if root is None:
            pytest.skip("no checkout above this file (the runner image copies tests/e2e/ to /app/e2e)")
        assert (root / SUITE_ROOT / Path(__file__).name).resolve() == Path(__file__).resolve()


class TestDedupeCovers:
    def test_ids_are_unique_order_preserving_and_non_empty_strings(self) -> None:
        assert dedupe_covers([("A", "B"), ("B", ""), ("C", 7)]) == ("A", "B", "C")
