"""
Tests for the check-research-id-type pre-commit hook.

Covers regressions:
- Substring exemption `"test_" in filepath` used to match any path
  containing 'test_' (e.g. protest_handler.py) and missed the *_test.py
  / /tests/ conventions.
- No comment/docstring skip — a comment like `# research_id: int`
  triggered a false positive.
"""

import subprocess
import sys
import tempfile
from pathlib import Path


HOOK_SCRIPT = (
    Path(__file__).parent.parent.parent
    / ".pre-commit-hooks"
    / "check-research-id-type.py"
)


def _run_hook(
    content: str, filename: str = "service.py"
) -> subprocess.CompletedProcess:
    with tempfile.TemporaryDirectory() as d:
        path = Path(d) / filename
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content)
        return subprocess.run(
            [sys.executable, str(HOOK_SCRIPT), str(path)],
            capture_output=True,
            text=True,
        )


class TestExemptionBugFixed:
    """Filename containing 'test_' as a substring must not silently exempt."""

    def test_protest_handler_is_scanned(self):
        """protest_handler.py contains substring 'test_' but is not a test file."""
        result = _run_hook(
            "def fn(research_id: int): pass\n", "protest_handler.py"
        )
        assert result.returncode == 1
        assert "research_id: int" in result.stdout

    def test_attest_module_is_scanned(self):
        result = _run_hook(
            "def fn(research_id: int): pass\n", "attest_module.py"
        )
        assert result.returncode == 1

    def test_contest_module_is_scanned(self):
        result = _run_hook(
            "def fn(research_id: int): pass\n", "contest_module.py"
        )
        assert result.returncode == 1


class TestTestFileExemptions:
    """All three test-file conventions must still be exempt."""

    def test_test_prefix_exempt(self):
        result = _run_hook("def fn(research_id: int): pass\n", "test_foo.py")
        assert result.returncode == 0

    def test_underscore_test_suffix_exempt(self):
        """`foo_test.py` (Go-style suffix) — newly supported."""
        result = _run_hook("def fn(research_id: int): pass\n", "foo_test.py")
        assert result.returncode == 0

    def test_tests_directory_exempt(self):
        """Files under a /tests/ directory — newly supported."""
        result = _run_hook(
            "def fn(research_id: int): pass\n", "tests/helpers.py"
        )
        assert result.returncode == 0

    def test_migration_path_exempt(self):
        result = _run_hook(
            "def fn(research_id: int): pass\n", "migrations/0001_init.py"
        )
        assert result.returncode == 0


class TestCommentSkip:
    """Comments and docstrings mentioning the bad patterns must not fire."""

    def test_comment_with_int_research_id_not_flagged(self):
        result = _run_hook("# research_id: int — historical note\n")
        assert result.returncode == 0

    def test_docstring_line_not_flagged(self):
        result = _run_hook(
            '"""Flask route <int:research_id> is deprecated."""\n'
        )
        assert result.returncode == 0

    def test_comment_with_flask_route_not_flagged(self):
        result = _run_hook("# Old: @app.route('/<int:research_id>/results')\n")
        assert result.returncode == 0


class TestRealViolationsStillFlagged:
    """Sanity check that real bad patterns are still caught."""

    def test_flask_int_route_flagged(self):
        result = _run_hook("@app.route('/<int:research_id>/results')\n")
        assert result.returncode == 1

    def test_int_type_hint_flagged(self):
        result = _run_hook("def fn(research_id: int): pass\n")
        assert result.returncode == 1

    def test_int_conversion_flagged(self):
        result = _run_hook("x = int(research_id)\n")
        assert result.returncode == 1

    def test_int_comparison_flagged(self):
        result = _run_hook("if research_id == 42: pass\n")
        assert result.returncode == 1
