"""Tests for database storage implementation."""

from local_deep_research.storage.database import DatabaseReportStorage


class TestDatabaseReportStorageInit:
    """Tests for DatabaseReportStorage initialization."""

    def test_stores_session(self, mock_session):
        """Should store provided session."""
        storage = DatabaseReportStorage(mock_session)
        assert storage.session is mock_session


class TestSaveReport:
    """Tests for save_report method."""

    def test_saves_content_to_existing_record(
        self, mock_session, mock_research_history, sample_report_content
    ):
        """Should save content to existing research record."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.save_report("test-uuid", sample_report_content)

        assert result is True
        assert mock_research_history.report_content == sample_report_content
        mock_session.commit.assert_called_once()

    def test_updates_metadata_when_provided(
        self,
        mock_session,
        mock_research_history,
        sample_report_content,
        sample_metadata,
    ):
        """Should update metadata when provided."""
        mock_research_history.research_meta = {"existing": "value"}
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        storage.save_report(
            "test-uuid", sample_report_content, metadata=sample_metadata
        )

        # Should merge metadata
        assert "existing" in mock_research_history.research_meta
        assert "query" in mock_research_history.research_meta

    def test_sets_metadata_when_none_exists(
        self,
        mock_session,
        mock_research_history,
        sample_report_content,
        sample_metadata,
    ):
        """Should set metadata when none exists."""
        mock_research_history.research_meta = None
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        storage.save_report(
            "test-uuid", sample_report_content, metadata=sample_metadata
        )

        assert mock_research_history.research_meta == sample_metadata

    def test_returns_false_when_record_not_found(
        self, mock_session, sample_report_content
    ):
        """Should return False when research record not found."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = None

        storage = DatabaseReportStorage(mock_session)
        result = storage.save_report("nonexistent", sample_report_content)

        assert result is False

    def test_returns_false_on_error(
        self, mock_session, mock_research_history, sample_report_content
    ):
        """Should return False on error and rollback."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history
        mock_session.commit.side_effect = Exception("commit error")

        storage = DatabaseReportStorage(mock_session)
        result = storage.save_report("test-uuid", sample_report_content)

        assert result is False
        mock_session.rollback.assert_called_once()


class TestGetReport:
    """Tests for get_report method."""

    def test_returns_content_when_exists(
        self, mock_session, mock_research_history
    ):
        """Should return report content when exists."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report("test-uuid")

        assert result == mock_research_history.report_content

    def test_returns_none_when_not_found(self, mock_session):
        """Should return None when record not found."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = None

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report("nonexistent")

        assert result is None

    def test_returns_none_when_content_is_none(
        self, mock_session, mock_research_history
    ):
        """Should return None when report_content is None."""
        mock_research_history.report_content = None
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report("test-uuid")

        assert result is None

    def test_returns_none_on_error(self, mock_session):
        """Should return None on error."""
        mock_session.query.side_effect = Exception("query error")

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report("test-uuid")

        assert result is None


class TestGetReportWithMetadata:
    """Tests for get_report_with_metadata method."""

    def test_returns_full_record(self, mock_session, mock_research_history):
        """Should return full record with metadata."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report_with_metadata("test-uuid")

        assert result["content"] == mock_research_history.report_content
        assert result["metadata"] == mock_research_history.research_meta
        assert result["query"] == mock_research_history.query
        assert result["mode"] == mock_research_history.mode
        assert "created_at" in result
        assert "completed_at" in result
        assert "duration_seconds" in result

    def test_returns_empty_metadata_when_none(
        self, mock_session, mock_research_history
    ):
        """Should return empty dict when research_meta is None."""
        mock_research_history.research_meta = None
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report_with_metadata("test-uuid")

        assert result["metadata"] == {}

    def test_returns_none_when_not_found(self, mock_session):
        """Should return None when not found."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = None

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report_with_metadata("nonexistent")

        assert result is None

    def test_returns_none_when_no_content(
        self, mock_session, mock_research_history
    ):
        """Should return None when report_content is None."""
        mock_research_history.report_content = None
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.get_report_with_metadata("test-uuid")

        assert result is None


class TestDeleteReport:
    """Tests for delete_report method."""

    def test_sets_content_to_none(self, mock_session, mock_research_history):
        """Should set report_content to None."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.delete_report("test-uuid")

        assert result is True
        assert mock_research_history.report_content is None
        mock_session.commit.assert_called_once()

    def test_returns_false_when_not_found(self, mock_session):
        """Should return False when not found."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = None

        storage = DatabaseReportStorage(mock_session)
        result = storage.delete_report("nonexistent")

        assert result is False

    def test_returns_false_on_error(self, mock_session, mock_research_history):
        """Should return False on error and rollback."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history
        mock_session.commit.side_effect = Exception("commit error")

        storage = DatabaseReportStorage(mock_session)
        result = storage.delete_report("test-uuid")

        assert result is False
        mock_session.rollback.assert_called_once()


class TestReportExists:
    """Tests for report_exists method."""

    def test_returns_true_when_content_exists(
        self, mock_session, mock_research_history
    ):
        """Should return True when report content exists."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.report_exists("test-uuid")

        assert result is True

    def test_returns_false_when_not_found(self, mock_session):
        """Should return False when not found."""
        mock_session.query.return_value.filter_by.return_value.first.return_value = None

        storage = DatabaseReportStorage(mock_session)
        result = storage.report_exists("nonexistent")

        assert result is False

    def test_returns_false_when_content_is_none(
        self, mock_session, mock_research_history
    ):
        """Should return False when report_content is None."""
        mock_research_history.report_content = None
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research_history

        storage = DatabaseReportStorage(mock_session)
        result = storage.report_exists("test-uuid")

        assert result is False

    def test_returns_false_on_error(self, mock_session):
        """Should return False on error."""
        mock_session.query.side_effect = Exception("query error")

        storage = DatabaseReportStorage(mock_session)
        result = storage.report_exists("test-uuid")

        assert result is False
