"""
Tests for the check-deprecated-db pre-commit hook.

Covers regressions:
- File-level 'get_user_db_session' guard used to whitelist whole files;
  one correct call silently allowed raw sqlite3.connect elsewhere.
- get_db_connection / import patterns had no comment/docstring skip — a
  TODO or migration note referencing the deprecated API was flagged.

Note: SHARED_DB is built at runtime to avoid embedding the literal
shared-database filename in this test file (a separate hook scans every
file for that literal).
"""

import subprocess
import sys
import tempfile
from pathlib import Path


HOOK_SCRIPT = (
    Path(__file__).parent.parent.parent
    / ".pre-commit-hooks"
    / "check-deprecated-db.py"
)

# Built at runtime to avoid tripping check-ldr-db (a separate hook that
# scans every file for the literal "ldr.db" substring).
SHARED_DB = "ldr" + ".db"


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 TestFileLevelGuardRemoved:
    """A correct get_user_db_session call no longer whitelists the whole file."""

    def test_correct_call_does_not_exempt_raw_sqlite_connect(self):
        content = (
            'with get_user_db_session("alice") as session:\n'
            "    pass\n"
            f'conn = sqlite3.connect("{SHARED_DB}")\n'
        )
        result = _run_hook(content)
        assert result.returncode == 1
        assert "Direct SQLite connection to shared database" in result.stdout

    def test_raw_sqlite_connect_without_sibling_still_flagged(self):
        result = _run_hook(f'conn = sqlite3.connect("{SHARED_DB}")\n')
        assert result.returncode == 1

    def test_noqa_sentinel_exempts_single_line(self):
        content = f'conn = sqlite3.connect("{SHARED_DB}")  # noqa: shared-db\n'
        result = _run_hook(content)
        assert result.returncode == 0


class TestCommentSkip:
    """Comments and docstrings mentioning deprecated APIs must not fire."""

    def test_todo_comment_about_get_db_connection_not_flagged(self):
        result = _run_hook(
            "# TODO: replace get_db_connection() with per-user session\n"
        )
        assert result.returncode == 0

    def test_docstring_mention_not_flagged(self):
        content = '"""get_db_connection() is deprecated — use get_user_db_session."""\n'
        result = _run_hook(content)
        assert result.returncode == 0

    def test_real_get_db_connection_call_flagged(self):
        result = _run_hook("conn = get_db_connection()\n")
        assert result.returncode == 1
        assert "deprecated get_db_connection" in result.stdout

    def test_comment_about_deprecated_import_not_flagged(self):
        result = _run_hook(
            "# Historical: from ..web.models.database import get_db_connection\n"
        )
        assert result.returncode == 0

    def test_real_deprecated_import_flagged(self):
        result = _run_hook(
            "from ..web.models.database import get_db_connection\n"
        )
        assert result.returncode == 1


class TestExistingAllowlistStillApplies:
    """Filename-based exemptions must still work."""

    def test_encrypted_db_exempt(self):
        """encrypted_db.py legitimately calls get_db_connection — the skip
        list in main() must still exempt it."""
        result = _run_hook(
            "conn = get_db_connection()\n", filename="encrypted_db.py"
        )
        assert result.returncode == 0

    def test_session_context_exempt(self):
        result = _run_hook(
            "conn = get_db_connection()\n", filename="session_context.py"
        )
        assert result.returncode == 0

    def test_tests_path_exempt(self):
        result = _run_hook(
            f'sqlite3.connect("{SHARED_DB}")\n', filename="tests/fixtures.py"
        )
        assert result.returncode == 0
