"""Tests for DocumentDeletionService."""

from unittest.mock import MagicMock, Mock, patch


from local_deep_research.research_library.deletion.services.document_deletion import (
    DocumentDeletionService,
)


class TestDocumentDeletionServiceInit:
    """Tests for DocumentDeletionService initialization."""

    def test_initializes_with_username(self):
        """Should initialize with username."""
        service = DocumentDeletionService(username="testuser")
        assert service.username == "testuser"


class TestDocumentDeletionServiceDeleteDocument:
    """Tests for delete_document method."""

    def test_returns_error_when_document_not_found(self):
        """Should return error when document doesn't exist."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_session.query.return_value.get.return_value = None

            result = service.delete_document("nonexistent-id")

        assert result["deleted"] is False
        assert "not found" in result["error"].lower()

    def test_deletes_document_successfully(self):
        """Should delete document and return stats."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            # Mock document
            mock_doc = MagicMock()
            mock_doc.id = "doc-123"
            mock_doc.title = "Test Document"
            mock_doc.filename = "test.pdf"
            mock_doc.storage_mode = "database"
            mock_doc.file_path = None
            mock_session.query.return_value.get.return_value = mock_doc

            with patch(
                "local_deep_research.research_library.deletion.services.document_deletion.CascadeHelper"
            ) as mock_helper:
                mock_helper.get_document_collections.return_value = ["col-1"]
                mock_helper.delete_document_chunks.return_value = 5
                mock_helper.get_document_blob_size.return_value = 1024
                mock_helper.delete_document_completely.return_value = True

                result = service.delete_document("doc-123")

        assert result["deleted"] is True
        assert result["document_id"] == "doc-123"
        assert result["chunks_deleted"] == 5
        assert result["blob_size"] == 1024

    def test_handles_exception_gracefully(self):
        """Should handle exceptions and rollback."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_session.query.side_effect = Exception("DB Error")

            result = service.delete_document("doc-123")

        assert result["deleted"] is False
        assert "error" in result


class TestDocumentDeletionServiceDeleteBlobOnly:
    """Tests for delete_blob_only method."""

    def test_returns_error_when_document_not_found(self):
        """Should return error when document doesn't exist."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_session.query.return_value.get.return_value = None

            result = service.delete_blob_only("nonexistent-id")

        assert result["deleted"] is False
        assert "not found" in result["error"].lower()

    def test_deletes_database_blob(self):
        """Should delete blob from database storage."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_doc = MagicMock()
            mock_doc.id = "doc-123"
            mock_doc.storage_mode = "database"
            mock_session.query.return_value.get.return_value = mock_doc

            with patch(
                "local_deep_research.research_library.deletion.services.document_deletion.CascadeHelper"
            ) as mock_helper:
                mock_helper.delete_document_blob.return_value = 2048

                result = service.delete_blob_only("doc-123")

        assert result["deleted"] is True
        assert result["bytes_freed"] == 2048
        assert result["storage_mode_updated"] is True

    def test_returns_error_for_none_storage_mode(self):
        """Should return error when document has no stored PDF."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_doc = MagicMock()
            mock_doc.id = "doc-123"
            mock_doc.storage_mode = "none"
            mock_session.query.return_value.get.return_value = mock_doc

            result = service.delete_blob_only("doc-123")

        assert result["deleted"] is False
        assert "no stored pdf" in result["error"].lower()


class TestDocumentDeletionServiceRemoveFromCollection:
    """Tests for remove_from_collection method."""

    def test_returns_error_when_document_not_found(self):
        """Should return error when document doesn't exist."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_session.query.return_value.get.return_value = None

            result = service.remove_from_collection("doc-123", "col-456")

        assert result["unlinked"] is False
        assert "not found" in result["error"].lower()

    def test_returns_error_when_not_in_collection(self):
        """Should return error when document not in collection."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_doc = MagicMock()
            mock_session.query.return_value.get.return_value = mock_doc
            mock_session.query.return_value.filter_by.return_value.first.return_value = None

            result = service.remove_from_collection("doc-123", "col-456")

        assert result["unlinked"] is False
        assert "not in this collection" in result["error"].lower()

    def test_unlinks_document_from_collection(self):
        """Should unlink document from collection."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_doc = MagicMock()
            mock_doc.id = "doc-123"
            mock_doc_collection = MagicMock()

            # Set up query chain
            mock_session.query.return_value.get.return_value = mock_doc
            mock_session.query.return_value.filter_by.return_value.first.return_value = mock_doc_collection

            with patch(
                "local_deep_research.research_library.deletion.services.document_deletion.CascadeHelper"
            ) as mock_helper:
                mock_helper.delete_document_chunks.return_value = 3
                mock_helper.count_document_in_collections.return_value = (
                    1  # Still in another collection
                )

                result = service.remove_from_collection("doc-123", "col-456")

        assert result["unlinked"] is True
        assert result["chunks_deleted"] == 3
        assert result["document_deleted"] is False


class TestDocumentDeletionServiceGetDeletionPreview:
    """Tests for get_deletion_preview method."""

    def test_returns_not_found_for_missing_document(self):
        """Should return found=False for missing document."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_session.query.return_value.get.return_value = None

            result = service.get_deletion_preview("nonexistent-id")

        assert result["found"] is False

    def test_returns_document_details(self):
        """Should return document details for preview."""
        service = DocumentDeletionService(username="testuser")

        with patch(
            "local_deep_research.research_library.deletion.services.document_deletion.get_user_db_session"
        ) as mock_get_session:
            mock_session = MagicMock()
            mock_cm = MagicMock()
            mock_cm.__enter__ = Mock(return_value=mock_session)
            mock_cm.__exit__ = Mock(return_value=None)
            mock_get_session.return_value = mock_cm

            mock_doc = MagicMock()
            mock_doc.id = "doc-123"
            mock_doc.title = "Test Document"
            mock_doc.filename = "test.pdf"
            mock_doc.file_type = "pdf"
            mock_doc.storage_mode = "database"
            mock_doc.text_content = "Some text content"
            mock_session.query.return_value.get.return_value = mock_doc
            mock_session.query.return_value.filter.return_value.count.return_value = 10

            with patch(
                "local_deep_research.research_library.deletion.services.document_deletion.CascadeHelper"
            ) as mock_helper:
                mock_helper.get_document_collections.return_value = [
                    "col-1",
                    "col-2",
                ]
                mock_helper.get_document_blob_size.return_value = 5120

                result = service.get_deletion_preview("doc-123")

        assert result["found"] is True
        assert result["title"] == "Test Document"
        assert result["collections_count"] == 2
        assert result["blob_size"] == 5120
