"""
Tests for the check-journal-quality-readonly pre-commit hook.

Ensures the compiled journal quality DB is only opened read-only at runtime.
The only allowed writer is build_db() in journal_quality/db.py.
"""

import sys
from importlib import import_module
from pathlib import Path


HOOKS_DIR = Path(__file__).parent.parent.parent / ".pre-commit-hooks"
sys.path.insert(0, str(HOOKS_DIR))

hook_module = import_module("check-journal-quality-readonly")
check_file_fn = hook_module.check_file

# Build the DB name dynamically so this test file is not flagged by
# the check-journal-quality-readonly hook itself.
_JQ_DB = "journal_" + "quality.db"
_JR_DB = "journal_" + "reference.db"


def _write_and_check(tmp_path, code: str, filename: str = "src/module.py"):
    """Write code to a temp file and check it."""
    p = tmp_path / filename
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text(code, encoding="utf-8")
    return check_file_fn(p)


class TestDetectsWritableOpens:
    """Ensures writable opens of the journal quality DB are caught."""

    def test_detects_sqlite_connect_without_mode_ro(self, tmp_path):
        code = f'conn = sqlite3.connect("{_JQ_DB}")\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) >= 1
        assert any("mode=ro" in e for e in errors)

    def test_detects_create_engine_without_mode_ro(self, tmp_path):
        code = f'engine = create_engine("sqlite:///{_JQ_DB}")\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) >= 1

    def test_detects_legacy_journal_reference_db(self, tmp_path):
        code = f'conn = sqlite3.connect("{_JR_DB}")\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) >= 1

    def test_detects_connect_in_fstring(self, tmp_path):
        code = f'conn = sqlite3.connect(f"{{path}}/{_JQ_DB}")\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) >= 1


class TestAllowsReadOnlyOpens:
    """Ensures read-only opens are allowed."""

    def test_allows_mode_ro(self, tmp_path):
        code = f'conn = sqlite3.connect(f"file:{{path}}/{_JQ_DB}?mode=ro&immutable=1", uri=True)\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_allows_mode_ro_uppercase(self, tmp_path):
        """SQLite accepts case-insensitive URI values — the hook should
        recognise `mode=RO` (and mixed case) as read-only intent too."""
        code = f'conn = sqlite3.connect(f"file:{{path}}/{_JQ_DB}?mode=RO&immutable=1", uri=True)\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_allows_mode_ro_mixed_case(self, tmp_path):
        code = f'conn = sqlite3.connect(f"file:{{path}}/{_JQ_DB}?mode=Ro", uri=True)\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_allows_mode_ro_with_whitespace(self, tmp_path):
        code = f'conn = sqlite3.connect(f"file:{{path}}/{_JQ_DB}?mode = ro", uri=True)\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0


class TestAllowsWriterModule:
    """Ensures the designated writer module can open writable."""

    def test_allows_build_db_writer(self, tmp_path):
        code = f'conn = sqlite3.connect("{_JQ_DB}")\n'
        errors = _write_and_check(
            tmp_path,
            code,
            filename="src/local_deep_research/journal_quality/db.py",
        )
        assert len(errors) == 0


class TestAllowsSafePatterns:
    """Ensures non-connect references are not flagged."""

    def test_allows_comments(self, tmp_path):
        code = f"# See {_JQ_DB} for data\n"
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_allows_path_existence_check(self, tmp_path):
        code = f'if Path("{_JQ_DB}").exists():\n    pass\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_allows_log_message(self, tmp_path):
        code = f'logger.info(f"Loading {_JQ_DB} from {{path}}")\n'
        errors = _write_and_check(tmp_path, code)
        assert len(errors) == 0

    def test_ignores_non_python_files(self, tmp_path):
        code = f'conn = sqlite3.connect("{_JQ_DB}")\n'
        errors = _write_and_check(tmp_path, code, filename="docs/readme.md")
        assert len(errors) == 0
