from __future__ import annotations

import re
from pathlib import Path

from llmdebug import _json as json

REPO_ROOT = Path(__file__).resolve().parents[1]


def _read_repo_text(path: str) -> str:
    return (REPO_ROOT / path).read_text(encoding="utf-8")


def _extract_toml_section(text: str, section_name: str) -> str:
    pattern = rf"^\[{re.escape(section_name)}\]\s*$\n(?P<body>.*?)(?=^\[.+\]\s*$|\Z)"
    match = re.search(pattern, text, flags=re.MULTILINE | re.DOTALL)
    assert match is not None, f"missing TOML section [{section_name}]"
    return match.group("body")


def _extract_cov_thresholds(text: str) -> set[int]:
    return {int(raw) for raw in re.findall(r"--cov-fail-under=(\d+)", text)}


def _extract_cov_commands(text: str) -> list[str]:
    return re.findall(r"^[^\n]*pytest[^\n]*--cov-fail-under=\d+[^\n]*$", text, flags=re.MULTILINE)


def _extract_xenon_tuples(text: str) -> set[tuple[str, str, str]]:
    tuples: set[tuple[str, str, str]] = set()
    for absolute, modules, average in re.findall(
        r"xenon\s+--max-absolute\s+([A-Z])\s+--max-modules\s+([A-Z])\s+--max-average\s+([A-Z])",
        text,
    ):
        tuples.add((absolute, modules, average))
    return tuples


def test_coverage_threshold_and_flags_aligned_between_pyproject_justfile_and_ci_workflow() -> None:
    pyproject = _read_repo_text("pyproject.toml")
    coverage_section = _extract_toml_section(pyproject, "tool.coverage.report")
    match = re.search(r"^\s*fail_under\s*=\s*(\d+)\s*$", coverage_section, flags=re.MULTILINE)
    assert match is not None, "missing coverage fail_under in pyproject"
    canonical_threshold = int(match.group(1))

    justfile = _read_repo_text("justfile")
    just_thresholds = _extract_cov_thresholds(justfile)
    assert just_thresholds == {canonical_threshold}
    just_cov_commands = _extract_cov_commands(justfile)
    assert just_cov_commands, "missing pytest coverage commands in justfile"
    for command in just_cov_commands:
        assert "--cov-branch" in command
        assert "--cov-report=json" in command

    ci_workflow = _read_repo_text(".github/workflows/ci-cd.yml")
    workflow_thresholds = _extract_cov_thresholds(ci_workflow)
    assert workflow_thresholds == {canonical_threshold}
    workflow_cov_commands = _extract_cov_commands(ci_workflow)
    assert workflow_cov_commands, "missing pytest coverage command in CI workflow"
    for command in workflow_cov_commands:
        assert "--cov-branch" in command
        assert "--cov-report=json" in command


def test_diff_cover_threshold_aligned_between_justfile_and_ci_workflow() -> None:
    justfile = _read_repo_text("justfile")
    ci_workflow = _read_repo_text(".github/workflows/ci-cd.yml")

    just_thresholds = {
        int(raw)
        for raw in re.findall(r"diff-cover[^\n]*--fail-under=(\d+)", justfile, flags=re.MULTILINE)
    }
    ci_thresholds = {
        int(raw)
        for raw in re.findall(
            r"diff-cover[^\n]*--fail-under=(\d+)", ci_workflow, flags=re.MULTILINE
        )
    }

    assert len(just_thresholds) == 1, "expected exactly one diff-cover threshold in justfile"
    assert len(ci_thresholds) == 1, "expected exactly one diff-cover threshold in CI workflow"
    assert just_thresholds == ci_thresholds


def test_xenon_thresholds_aligned_between_justfile_and_ci_workflow() -> None:
    justfile = _read_repo_text("justfile")
    ci_workflow = _read_repo_text(".github/workflows/ci-cd.yml")

    just_tuples = _extract_xenon_tuples(justfile)
    ci_tuples = _extract_xenon_tuples(ci_workflow)

    assert len(just_tuples) == 1, "expected one canonical xenon tuple in justfile"
    assert len(ci_tuples) == 1, "expected one canonical xenon tuple in CI workflow"
    assert just_tuples == ci_tuples


def test_ci_workflow_wires_coverage_no_regression_gate() -> None:
    ci_workflow = _read_repo_text(".github/workflows/ci-cd.yml")
    assert "scripts/quality/check_coverage_no_regression.py" in ci_workflow
    assert "--coverage-json coverage.json" in ci_workflow
    assert "--baseline-json quality/coverage_baseline.json" in ci_workflow


def test_coverage_baseline_file_has_required_schema() -> None:
    baseline_path = REPO_ROOT / "quality" / "coverage_baseline.json"
    assert baseline_path.exists(), "missing quality/coverage_baseline.json"
    payload = json.loads(baseline_path.read_text(encoding="utf-8"))
    assert isinstance(payload, dict)
    assert "line_percent" in payload
    assert "branch_percent" in payload
    assert "source" in payload
    assert "updated_at_utc" in payload
    assert isinstance(payload["line_percent"], (int, float))
    assert isinstance(payload["branch_percent"], (int, float))
    assert isinstance(payload["source"], str)
    assert isinstance(payload["updated_at_utc"], str)


def test_deptry_dep002_ignores_eval_only_analytics_dependencies() -> None:
    pyproject = _read_repo_text("pyproject.toml")
    deptry_ignores_section = _extract_toml_section(pyproject, "tool.deptry.per_rule_ignores")
    match = re.search(
        r"^\s*DEP002\s*=\s*\[(?P<body>.*?)\]\s*$",
        deptry_ignores_section,
        flags=re.MULTILINE | re.DOTALL,
    )
    assert match is not None, "missing DEP002 ignore list in deptry config"
    dep002_ignored_packages = set(re.findall(r'"([^"]+)"', match.group("body")))
    assert {"polars", "scikit-learn", "scipy"}.issubset(dep002_ignored_packages)
