"""Tests for storage factory."""

from unittest.mock import MagicMock, patch

import pytest

from local_deep_research.storage.factory import (
    get_report_storage,
    get_request_report_storage,
    set_request_report_storage,
    clear_request_report_storage,
)
from local_deep_research.storage.database_with_file_backup import (
    DatabaseWithFileBackupStorage,
)
from local_deep_research.config.thread_settings import NoSettingsContextError


class TestGetReportStorage:
    """Tests for get_report_storage factory function."""

    def test_raises_when_session_is_none(self):
        """Should raise ValueError when session is None."""
        with pytest.raises(ValueError, match="Database session is required"):
            get_report_storage(session=None)

    def test_returns_database_with_file_backup_storage(self, mock_session):
        """Should return DatabaseWithFileBackupStorage instance."""
        with patch(
            "local_deep_research.storage.factory.get_setting_from_snapshot"
        ) as mock_get:
            mock_get.return_value = False
            storage = get_report_storage(session=mock_session)

        assert isinstance(storage, DatabaseWithFileBackupStorage)

    def test_uses_provided_enable_file_backup_true(self, mock_session):
        """Should use enable_file_backup=True when explicitly provided."""
        storage = get_report_storage(
            session=mock_session, enable_file_backup=True
        )

        assert storage.enable_file_storage is True

    def test_uses_provided_enable_file_backup_false(self, mock_session):
        """Should use enable_file_backup=False when explicitly provided."""
        storage = get_report_storage(
            session=mock_session, enable_file_backup=False
        )

        assert storage.enable_file_storage is False

    def test_reads_setting_when_enable_file_backup_is_none(self, mock_session):
        """Should read from settings when enable_file_backup not provided."""
        with patch(
            "local_deep_research.storage.factory.get_setting_from_snapshot"
        ) as mock_get:
            mock_get.return_value = True
            storage = get_report_storage(session=mock_session)

        mock_get.assert_called_once_with(
            "report.enable_file_backup",
            settings_snapshot=None,
        )
        assert storage.enable_file_storage is True

    def test_passes_settings_snapshot_to_get_setting(self, mock_session):
        """Should pass settings_snapshot to get_setting_from_snapshot."""
        snapshot = {"report": {"enable_file_backup": True}}

        with patch(
            "local_deep_research.storage.factory.get_setting_from_snapshot"
        ) as mock_get:
            mock_get.return_value = True
            get_report_storage(session=mock_session, settings_snapshot=snapshot)

        mock_get.assert_called_once_with(
            "report.enable_file_backup",
            settings_snapshot=snapshot,
        )

    def test_defaults_to_false_when_no_settings_context(self, mock_session):
        """Should default to False when NoSettingsContextError raised."""
        with patch(
            "local_deep_research.storage.factory.get_setting_from_snapshot"
        ) as mock_get:
            mock_get.side_effect = NoSettingsContextError("No context")
            storage = get_report_storage(session=mock_session)

        assert storage.enable_file_storage is False


class TestRequestStorageHelpers:
    """Tests for request context storage helpers."""

    def test_get_returns_none_initially(self):
        """Should return None when no storage set."""
        clear_request_report_storage()  # Ensure clean state
        result = get_request_report_storage()
        assert result is None

    def test_set_and_get(self, mock_session):
        """Should store and retrieve storage instance."""
        storage = MagicMock()

        try:
            set_request_report_storage(storage)
            result = get_request_report_storage()
            assert result is storage
        finally:
            clear_request_report_storage()

    def test_clear_removes_storage(self, mock_session):
        """Should remove storage instance."""
        storage = MagicMock()

        set_request_report_storage(storage)
        clear_request_report_storage()
        result = get_request_report_storage()

        assert result is None

    def test_set_overwrites_previous(self, mock_session):
        """Should overwrite previous storage instance."""
        storage1 = MagicMock()
        storage2 = MagicMock()

        try:
            set_request_report_storage(storage1)
            set_request_report_storage(storage2)
            result = get_request_report_storage()
            assert result is storage2
        finally:
            clear_request_report_storage()
