"""
Tests for SQLCipher missing scenario.

Verifies that users get helpful error messages when SQLCipher is not installed
and that the LDR_BOOTSTRAP_ALLOW_UNENCRYPTED workaround works.
"""

import os
import pytest
from unittest.mock import patch

from tests.test_utils import add_src_to_path

add_src_to_path()


def _clear_allow_unencrypted_env():
    """Clear both canonical and deprecated env vars."""
    os.environ.pop("LDR_BOOTSTRAP_ALLOW_UNENCRYPTED", None)
    os.environ.pop("LDR_ALLOW_UNENCRYPTED", None)


class TestSQLCipherMissing:
    """Test behavior when SQLCipher is not available."""

    def test_error_message_mentions_sqlcipher(self):
        """Error message should mention SQLCipher so users know what's missing."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        old_canonical = os.environ.pop("LDR_BOOTSTRAP_ALLOW_UNENCRYPTED", None)
        old_deprecated = os.environ.pop("LDR_ALLOW_UNENCRYPTED", None)

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                with pytest.raises(RuntimeError) as exc_info:
                    DatabaseManager()

                error_msg = str(exc_info.value)
                assert "SQLCipher" in error_msg, (
                    f"Error should mention SQLCipher. Got: {error_msg}"
                )
        finally:
            if old_canonical is not None:
                os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = old_canonical
            if old_deprecated is not None:
                os.environ["LDR_ALLOW_UNENCRYPTED"] = old_deprecated

    def test_error_message_mentions_workaround(self):
        """Error message should mention LDR_BOOTSTRAP_ALLOW_UNENCRYPTED workaround."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        old_canonical = os.environ.pop("LDR_BOOTSTRAP_ALLOW_UNENCRYPTED", None)
        old_deprecated = os.environ.pop("LDR_ALLOW_UNENCRYPTED", None)

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                with pytest.raises(RuntimeError) as exc_info:
                    DatabaseManager()

                error_msg = str(exc_info.value)
                assert "LDR_BOOTSTRAP_ALLOW_UNENCRYPTED" in error_msg, (
                    f"Error should mention workaround. Got: {error_msg}"
                )
        finally:
            if old_canonical is not None:
                os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = old_canonical
            if old_deprecated is not None:
                os.environ["LDR_ALLOW_UNENCRYPTED"] = old_deprecated

    def test_canonical_workaround_allows_startup_without_encryption(self):
        """LDR_BOOTSTRAP_ALLOW_UNENCRYPTED=true should allow startup without SQLCipher."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        old_canonical = os.environ.get("LDR_BOOTSTRAP_ALLOW_UNENCRYPTED")
        old_deprecated = os.environ.get("LDR_ALLOW_UNENCRYPTED")
        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise
                manager = DatabaseManager()
                assert manager.has_encryption is False, (
                    "With workaround and no SQLCipher, has_encryption should be False"
                )
        finally:
            _clear_allow_unencrypted_env()
            if old_canonical is not None:
                os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = old_canonical
            if old_deprecated is not None:
                os.environ["LDR_ALLOW_UNENCRYPTED"] = old_deprecated

    def test_deprecated_workaround_still_works(self):
        """Deprecated LDR_ALLOW_UNENCRYPTED=true should still allow startup (backward compat)."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        old_canonical = os.environ.get("LDR_BOOTSTRAP_ALLOW_UNENCRYPTED")
        old_deprecated = os.environ.get("LDR_ALLOW_UNENCRYPTED")
        _clear_allow_unencrypted_env()
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise (backward compatibility)
                manager = DatabaseManager()
                assert manager.has_encryption is False, (
                    "With deprecated workaround and no SQLCipher, has_encryption should be False"
                )
        finally:
            _clear_allow_unencrypted_env()
            if old_canonical is not None:
                os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = old_canonical
            if old_deprecated is not None:
                os.environ["LDR_ALLOW_UNENCRYPTED"] = old_deprecated

    def test_db_manager_has_encryption_is_boolean(self):
        """db_manager.has_encryption should be a boolean."""
        from local_deep_research.database.encrypted_db import db_manager

        assert isinstance(db_manager.has_encryption, bool), (
            f"has_encryption should be bool, got {type(db_manager.has_encryption)}"
        )


class TestAllowUnencryptedEdgeCases:
    """Edge cases for LDR_BOOTSTRAP_ALLOW_UNENCRYPTED fallback.

    The allow_unencrypted setting uses the BooleanSetting from the env
    settings registry, which accepts "true", "1", "yes", "on", "enabled"
    (case-insensitive) as truthy values and handles deprecated alias
    fallback automatically.
    """

    def test_canonical_empty_string_does_not_fall_through(self):
        """Empty string canonical should NOT fall through to deprecated.

        When LDR_BOOTSTRAP_ALLOW_UNENCRYPTED="" is set, it takes precedence
        and the check (empty_string or "").lower() == "true" is False.
        """
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = ""
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should raise because empty string is not "true"
                with pytest.raises(RuntimeError):
                    DatabaseManager()
        finally:
            _clear_allow_unencrypted_env()

    def test_uppercase_true_not_accepted(self):
        """'TRUE' (uppercase) is not accepted as true.

        The code uses .lower() == "true", so "TRUE".lower() == "true" is True.
        """
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "TRUE"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - "TRUE".lower() == "true" is True
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_mixed_case_true_accepted(self):
        """'True' (mixed case) is accepted as true due to .lower()."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "True"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - "True".lower() == "true" is True
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_whitespace_padded_true_not_accepted(self):
        """' true ' (whitespace padded) is not accepted as true.

        The code doesn't strip whitespace, so " true " != "true".
        """
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = " true "

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should raise - " true " != "true"
                with pytest.raises(RuntimeError):
                    DatabaseManager()
        finally:
            _clear_allow_unencrypted_env()

    def test_yes_accepted_as_true(self):
        """'yes' is accepted as true by BooleanSetting."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "yes"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - BooleanSetting accepts "yes"
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_one_accepted_as_true(self):
        """'1' is accepted as true by BooleanSetting."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "1"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - BooleanSetting accepts "1"
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_canonical_false_does_not_check_deprecated(self):
        """canonical='false' should NOT fall through to deprecated='true'.

        Once canonical is set (to any value), deprecated is not checked.
        """
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = "false"
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should raise - canonical "false" takes precedence
                with pytest.raises(RuntimeError):
                    DatabaseManager()
        finally:
            _clear_allow_unencrypted_env()

    def test_empty_canonical_with_deprecated_true_raises(self):
        """Empty canonical with deprecated='true' - empty takes precedence.

        When canonical is "", the deprecated is not checked because
        canonical is "set" (to empty string).
        """
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_BOOTSTRAP_ALLOW_UNENCRYPTED"] = ""
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should raise - empty string canonical takes precedence
                with pytest.raises(RuntimeError):
                    DatabaseManager()
        finally:
            _clear_allow_unencrypted_env()

    def test_only_deprecated_set_to_true_works(self):
        """When only deprecated is set to 'true', it should work."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "true"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - deprecated "true" works
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_deprecated_uppercase_true_accepted(self):
        """Deprecated 'TRUE' (uppercase) works due to .lower()."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()
        os.environ["LDR_ALLOW_UNENCRYPTED"] = "TRUE"

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                # Should NOT raise - "TRUE".lower() == "true"
                manager = DatabaseManager()
                assert manager.has_encryption is False
        finally:
            _clear_allow_unencrypted_env()

    def test_neither_set_raises_runtime_error(self):
        """When neither canonical nor deprecated is set, RuntimeError is raised."""
        from local_deep_research.database.encrypted_db import (
            DatabaseManager,
        )

        _clear_allow_unencrypted_env()

        try:
            with patch(
                "local_deep_research.database.encrypted_db.get_sqlcipher_module"
            ) as mock_get:
                mock_get.side_effect = ImportError(
                    "No module named 'sqlcipher3'"
                )

                with pytest.raises(RuntimeError):
                    DatabaseManager()
        finally:
            _clear_allow_unencrypted_env()
