"""后端单测统一 runner 的分片与 CI 调用合同。"""

from pathlib import Path

import pytest

from tests import run as test_runner


ROOT = Path(__file__).resolve().parents[1]
WORKFLOW = ROOT / ".github" / "workflows" / "test.yml"


def _test_files(count: int) -> list[Path]:
    """构造按字典序排列的测试文件路径。"""
    return [Path(f"test_{index:03d}.py") for index in range(count)]


def test_split_test_files_uses_stable_contiguous_chunks() -> None:
    """文件分片必须稳定覆盖全集，且与既有 CI 的连续均分语义一致。"""
    test_files = _test_files(10)

    shards = test_runner.split_test_files(test_files, shard_count=4)

    assert [len(shard) for shard in shards] == [3, 3, 3, 1]
    assert [test_file for shard in shards for test_file in shard] == test_files


def test_main_defaults_to_four_parallel_shards(monkeypatch) -> None:
    """无 runner 参数时应并行执行四个独立 pytest 文件分片。"""
    test_files = _test_files(10)
    captured = {}
    monkeypatch.setattr(test_runner, "collect_test_files", lambda: test_files)

    def fake_run_parallel(shards, pytest_args):
        captured["shards"] = shards
        captured["pytest_args"] = pytest_args
        return 0

    monkeypatch.setattr(test_runner, "run_parallel_shards", fake_run_parallel)

    assert test_runner.main(["-q", "--maxfail=1"]) == 0
    assert [len(shard) for shard in captured["shards"]] == [3, 3, 3, 1]
    assert captured["pytest_args"] == ["-q", "--maxfail=1"]


def test_main_runs_requested_ci_shard_in_current_process(monkeypatch) -> None:
    """CI 指定分片时只运行该分片，并继续透传 pytest 参数。"""
    test_files = _test_files(10)
    captured = {}
    monkeypatch.setattr(test_runner, "collect_test_files", lambda: test_files)

    def fake_run_pytest(paths, pytest_args):
        captured["paths"] = paths
        captured["pytest_args"] = pytest_args
        return 0

    monkeypatch.setattr(test_runner, "run_pytest", fake_run_pytest)

    assert test_runner.main(["--shard", "2/4", "-q"]) == 0
    assert captured["paths"] == test_files[3:6]
    assert captured["pytest_args"] == ["-q"]


def test_main_serial_preserves_legacy_full_suite_entry(monkeypatch) -> None:
    """串行模式必须保留 tests 根目录加 pytest 参数透传的旧入口。"""
    captured = {}

    def fake_run_pytest(paths, pytest_args):
        captured["paths"] = paths
        captured["pytest_args"] = pytest_args
        return 0

    monkeypatch.setattr(test_runner, "run_pytest", fake_run_pytest)

    assert test_runner.main(["--serial", "-q", "--maxfail=1"]) == 0
    assert captured["paths"] == [test_runner.TESTS_DIR]
    assert captured["pytest_args"] == ["-q", "--maxfail=1"]


@pytest.mark.parametrize("value", ["0/4", "5/4", "1/0", "invalid"])
def test_invalid_shard_values_are_rejected(value: str) -> None:
    """分片参数必须使用有效的一基 N/TOTAL 范围。"""
    with pytest.raises(SystemExit, match="2"):
        test_runner.parse_args(["--shard", value])


def test_workflow_uses_the_shared_runner_contract() -> None:
    """CI 不得另行维护 shell 分片算法，覆盖率必须显式使用串行模式。"""
    workflow = WORKFLOW.read_text(encoding="utf-8")

    assert 'python tests/run.py --shard "${{ matrix.shard }}"' in workflow
    assert "python -m coverage run tests/run.py --serial" in workflow
    assert "mapfile" not in workflow
    assert "SHARD_INDEX" not in workflow
