"""Tests that CI/CD workflows and quality-gate config stay in sync with pyproject.toml."""

from __future__ import annotations

import re
from pathlib import Path

from llmdebug import _json as json

REPO_ROOT = Path(__file__).resolve().parents[1]
CI_WORKFLOW_PATH = ".github/workflows/ci-cd.yml"
RELEASE_WORKFLOW_PATH = ".github/workflows/release.yml"
QUALITY_ACTION_PATH = ".github/actions/run-quality-contract/action.yml"


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_and_justfile() -> 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


def test_diff_cover_threshold_defined_once_in_justfile() -> None:
    justfile = _read_repo_text("justfile")

    just_thresholds = {
        int(raw)
        for raw in re.findall(r"diff-cover[^\n]*--fail-under=(\d+)", justfile, flags=re.MULTILINE)
    }
    assert len(just_thresholds) == 1, "expected exactly one diff-cover threshold in justfile"


def test_xenon_thresholds_defined_once_in_justfile() -> None:
    justfile = _read_repo_text("justfile")

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


def test_shared_quality_action_delegates_to_just_contract() -> None:
    shared_action = _read_repo_text(QUALITY_ACTION_PATH)
    assert "just quality" in shared_action
    assert "just diff-coverage" in shared_action


def test_ci_and_release_workflows_use_shared_quality_action() -> None:
    ci_workflow = _read_repo_text(CI_WORKFLOW_PATH)
    release_workflow = _read_repo_text(RELEASE_WORKFLOW_PATH)
    assert "uses: ./.github/actions/run-quality-contract" in ci_workflow
    assert "uses: ./.github/actions/run-quality-contract" in release_workflow


def test_just_quality_wires_coverage_no_regression_gate() -> None:
    justfile = _read_repo_text("justfile")
    assert "coverage-no-regression" in justfile
    assert "scripts/quality/check_coverage_no_regression.py" in justfile
    assert "--coverage-json coverage.json" in justfile
    assert "--baseline-json quality/coverage_baseline.json" in justfile


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_type_coverage_baseline_file_has_required_schema() -> None:
    baseline_path = REPO_ROOT / "quality" / "type_coverage_baseline.json"
    assert baseline_path.exists(), "missing quality/type_coverage_baseline.json"
    payload = json.loads(baseline_path.read_text(encoding="utf-8"))
    assert isinstance(payload, dict)
    assert "completeness_percent" in payload
    assert "exported_known" in payload
    assert "exported_ambiguous" in payload
    assert "exported_unknown" in payload
    assert "source" in payload
    assert "updated_at_utc" in payload
    assert isinstance(payload["completeness_percent"], (int, float))
    assert isinstance(payload["exported_known"], int)
    assert isinstance(payload["exported_ambiguous"], int)
    assert isinstance(payload["exported_unknown"], int)
    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)


def test_just_quality_wires_type_coverage_regression_gate() -> None:
    justfile = _read_repo_text("justfile")
    assert "type-coverage-strict" in justfile
    assert "scripts/quality/check_type_coverage.py --strict" in justfile
    quality_match = re.search(r"^quality:\s+(?P<body>.+)$", justfile, flags=re.MULTILINE)
    assert quality_match is not None
    assert "type-coverage-strict" in quality_match.group("body")


def test_justfile_exposes_eval_typing_and_integration_test_recipes() -> None:
    justfile = _read_repo_text("justfile")
    assert re.search(r"^typecheck-evals:\s*$", justfile, flags=re.MULTILINE)
    assert "pyright -p pyrightconfig.evals.json" in justfile
    assert re.search(r"^test-integration:\s*$", justfile, flags=re.MULTILINE)
    assert "pytest -m integration -v" in justfile


def test_default_test_recipes_skip_integration_marker() -> None:
    justfile = _read_repo_text("justfile")
    assert 'pytest -m "not integration"' in justfile


def test_ci_workflow_surfaces_eval_typecheck_non_blocking() -> None:
    ci_workflow = _read_repo_text(CI_WORKFLOW_PATH)
    assert "Run eval static checks (informational)" in ci_workflow
    assert "continue-on-error: true" in ci_workflow
    assert "just typecheck-evals" in ci_workflow


def test_ci_workflow_runs_integration_lane() -> None:
    ci_workflow = _read_repo_text(CI_WORKFLOW_PATH)
    assert "Run integration test lane" in ci_workflow
    assert 'PYTHON_VERSION="3.13" just test-integration' in ci_workflow


def test_docs_reference_staged_type_and_integration_commands() -> None:
    contributing = _read_repo_text("CONTRIBUTING.md")
    testing_guide = _read_repo_text("docs/testing-guide.md")
    tests_readme = _read_repo_text("tests/README.md")
    quality_map = _read_repo_text("docs/quality-map.md")

    for text in (contributing, testing_guide, tests_readme, quality_map):
        assert "test-integration" in text
        assert "typecheck-evals" in text

    assert "type-coverage-strict" in contributing
    assert "quality/type_coverage_baseline.json" in quality_map
