"""
Document deletion service.

Handles:
- Full document deletion with proper cascade cleanup
- Blob-only deletion (remove PDF, keep text)
- Remove from collection (unlink or delete if orphaned)
"""

from typing import Dict, Any

from loguru import logger

from ....constants import FILE_PATH_BLOB_DELETED
from ....database.models.library import (
    Document,
    DocumentChunk,
    DocumentCollection,
)
from ....database.session_context import get_user_db_session
from ..utils.cascade_helper import CascadeHelper


class DocumentDeletionService:
    """Service for document deletion operations."""

    def __init__(self, username: str):
        """
        Initialize document deletion service.

        Args:
            username: Username for database session
        """
        self.username = username

    def delete_document(self, document_id: str) -> Dict[str, Any]:
        """
        Delete a document and ALL related data.

        This method ensures complete cleanup:
        - DocumentChunks (no FK constraint, manual cleanup required)
        - DocumentBlob (CASCADE handles, but we track for stats)
        - Filesystem files
        - FAISS index entries
        - DownloadTracker update
        - DocumentCollection links (CASCADE)
        - RagDocumentStatus (CASCADE)

        Args:
            document_id: ID of the document to delete

        Returns:
            Dict with deletion details:
            {
                "deleted": True/False,
                "document_id": str,
                "title": str,
                "blob_deleted": bool,
                "blob_size": int,
                "chunks_deleted": int,
                "collections_unlinked": int,
                "error": str (if failed)
            }
        """
        with get_user_db_session(self.username) as session:
            try:
                # Get document
                document = session.query(Document).get(document_id)
                if not document:
                    return {
                        "deleted": False,
                        "document_id": document_id,
                        "error": "Document not found",
                    }

                title = document.title or document.filename or "Untitled"
                result: Dict[str, Any] = {
                    "deleted": False,
                    "document_id": document_id,
                    "title": title,
                    "blob_deleted": False,
                    "blob_size": 0,
                    "chunks_deleted": 0,
                    "collections_unlinked": 0,
                    "file_deleted": False,
                }

                # 1. Get collections before deletion for chunk cleanup
                collections = CascadeHelper.get_document_collections(
                    session, document_id
                )
                result["collections_unlinked"] = len(collections)

                # 2. Delete DocumentChunks for ALL collections this document is in
                total_chunks_deleted = 0
                for collection_id in collections:
                    collection_name = f"collection_{collection_id}"
                    chunks_deleted = CascadeHelper.delete_document_chunks(
                        session, document_id, collection_name
                    )
                    total_chunks_deleted += chunks_deleted
                result["chunks_deleted"] = total_chunks_deleted

                # 3. Get blob size before deletion (for stats)
                result["blob_size"] = CascadeHelper.get_document_blob_size(
                    session, document_id
                )
                result["blob_deleted"] = result["blob_size"] > 0

                # 4. Delete filesystem file if exists
                if document.storage_mode == "filesystem" and document.file_path:
                    from ...utils import get_absolute_path_from_settings

                    try:
                        file_path = get_absolute_path_from_settings(
                            document.file_path
                        )
                        if file_path:
                            result["file_deleted"] = (
                                CascadeHelper.delete_filesystem_file(
                                    str(file_path)
                                )
                            )
                    except Exception:
                        logger.exception("Failed to delete filesystem file")

                # 5. Update DownloadTracker
                CascadeHelper.update_download_tracker(session, document)

                # 6. Delete the document and all related records
                CascadeHelper.delete_document_completely(session, document_id)
                session.commit()

                result["deleted"] = True
                logger.info(
                    f"Deleted document {document_id[:8]}... ({title}): "
                    f"{total_chunks_deleted} chunks, "
                    f"{result['blob_size']} bytes blob"
                )

                return result

            except Exception:
                logger.exception(f"Failed to delete document {document_id}")
                session.rollback()
                return {
                    "deleted": False,
                    "document_id": document_id,
                    "error": "Failed to delete document",
                }

    def delete_blob_only(self, document_id: str) -> Dict[str, Any]:
        """
        Delete PDF binary but keep document metadata and text content.

        This saves database space while preserving searchability.

        Args:
            document_id: ID of the document

        Returns:
            Dict with deletion details:
            {
                "deleted": True/False,
                "document_id": str,
                "bytes_freed": int,
                "storage_mode_updated": bool,
                "error": str (if failed)
            }
        """
        with get_user_db_session(self.username) as session:
            try:
                # Get document
                document = session.query(Document).get(document_id)
                if not document:
                    return {
                        "deleted": False,
                        "document_id": document_id,
                        "bytes_freed": 0,
                        "error": "Document not found",
                    }

                result = {
                    "deleted": False,
                    "document_id": document_id,
                    "bytes_freed": 0,
                    "storage_mode_updated": False,
                }

                # Handle based on storage mode
                if document.storage_mode == "database":
                    # Delete blob from database
                    result["bytes_freed"] = CascadeHelper.delete_document_blob(
                        session, document_id
                    )

                elif document.storage_mode == "filesystem":
                    # Delete filesystem file
                    from ...utils import get_absolute_path_from_settings

                    if document.file_path:
                        try:
                            file_path = get_absolute_path_from_settings(
                                document.file_path
                            )
                            if file_path and file_path.is_file():
                                result["bytes_freed"] = file_path.stat().st_size
                                CascadeHelper.delete_filesystem_file(
                                    str(file_path)
                                )
                        except Exception:
                            logger.exception("Failed to delete filesystem file")

                else:
                    # No blob to delete
                    return {
                        "deleted": False,
                        "document_id": document_id,
                        "bytes_freed": 0,
                        "error": "Document has no stored PDF (storage_mode is 'none')",
                    }

                # Update document to indicate blob is deleted
                document.storage_mode = "none"
                document.file_path = FILE_PATH_BLOB_DELETED
                result["storage_mode_updated"] = True

                session.commit()
                result["deleted"] = True

                logger.info(
                    f"Deleted blob for document {document_id[:8]}...: "
                    f"{result['bytes_freed']} bytes freed"
                )

                return result

            except Exception:
                logger.exception(
                    f"Failed to delete blob for document {document_id}"
                )
                session.rollback()
                return {
                    "deleted": False,
                    "document_id": document_id,
                    "bytes_freed": 0,
                    "error": "Failed to delete document blob",
                }

    def remove_from_collection(
        self,
        document_id: str,
        collection_id: str,
    ) -> Dict[str, Any]:
        """
        Remove document from a collection.

        If the document is not in any other collection after removal,
        it will be completely deleted.

        Args:
            document_id: ID of the document
            collection_id: ID of the collection

        Returns:
            Dict with operation details:
            {
                "unlinked": True/False,
                "document_deleted": bool,
                "document_id": str,
                "collection_id": str,
                "chunks_deleted": int,
                "error": str (if failed)
            }
        """
        with get_user_db_session(self.username) as session:
            try:
                # Verify document exists
                document = session.query(Document).get(document_id)
                if not document:
                    return {
                        "unlinked": False,
                        "document_deleted": False,
                        "document_id": document_id,
                        "collection_id": collection_id,
                        "error": "Document not found",
                    }

                # Verify collection exists and document is in it
                doc_collection = (
                    session.query(DocumentCollection)
                    .filter_by(
                        document_id=document_id, collection_id=collection_id
                    )
                    .first()
                )

                if not doc_collection:
                    return {
                        "unlinked": False,
                        "document_deleted": False,
                        "document_id": document_id,
                        "collection_id": collection_id,
                        "error": "Document not in this collection",
                    }

                result = {
                    "unlinked": False,
                    "document_deleted": False,
                    "document_id": document_id,
                    "collection_id": collection_id,
                    "chunks_deleted": 0,
                }

                # Delete chunks for this document in this collection
                collection_name = f"collection_{collection_id}"
                result["chunks_deleted"] = CascadeHelper.delete_document_chunks(
                    session, document_id, collection_name
                )

                # Remove the link
                session.delete(doc_collection)
                session.flush()

                # Check if document is in any other collection
                remaining_count = CascadeHelper.count_document_in_collections(
                    session, document_id
                )

                if remaining_count == 0:
                    # Document is orphaned - delete it completely
                    # Note: We're already in a session, so we need to do this
                    # directly rather than calling delete_document()
                    logger.info(
                        f"Document {document_id[:8]}... is orphaned, deleting"
                    )

                    # Delete remaining chunks (shouldn't be any, but be safe)
                    session.query(DocumentChunk).filter(
                        DocumentChunk.source_id == document_id,
                        DocumentChunk.source_type == "document",
                    ).delete(synchronize_session=False)

                    # Update DownloadTracker
                    CascadeHelper.update_download_tracker(session, document)

                    # Delete filesystem file if applicable
                    if (
                        document.storage_mode == "filesystem"
                        and document.file_path
                    ):
                        from ...utils import get_absolute_path_from_settings

                        try:
                            file_path = get_absolute_path_from_settings(
                                document.file_path
                            )
                            if file_path:
                                CascadeHelper.delete_filesystem_file(
                                    str(file_path)
                                )
                        except Exception:
                            logger.exception("Failed to delete filesystem file")

                    # Delete document and all related records
                    CascadeHelper.delete_document_completely(
                        session, document_id
                    )
                    result["document_deleted"] = True

                session.commit()
                result["unlinked"] = True

                logger.info(
                    f"Removed document {document_id[:8]}... from collection "
                    f"{collection_id[:8]}... "
                    f"(deleted={result['document_deleted']})"
                )

                return result

            except Exception:
                logger.exception(
                    f"Failed to remove document {document_id} "
                    f"from collection {collection_id}"
                )
                session.rollback()
                return {
                    "unlinked": False,
                    "document_deleted": False,
                    "document_id": document_id,
                    "collection_id": collection_id,
                    "error": "Failed to remove document from collection",
                }

    def get_deletion_preview(self, document_id: str) -> Dict[str, Any]:
        """
        Get a preview of what will be deleted.

        Useful for showing the user what will happen before confirming.

        Args:
            document_id: ID of the document

        Returns:
            Dict with preview information
        """
        with get_user_db_session(self.username) as session:
            document = session.query(Document).get(document_id)
            if not document:
                return {"found": False, "document_id": document_id}

            collections = CascadeHelper.get_document_collections(
                session, document_id
            )

            # Count chunks
            total_chunks = (
                session.query(DocumentChunk)
                .filter(
                    DocumentChunk.source_id == document_id,
                    DocumentChunk.source_type == "document",
                )
                .count()
            )

            blob_size = CascadeHelper.get_document_blob_size(
                session, document_id
            )

            return {
                "found": True,
                "document_id": document_id,
                "title": document.title or document.filename or "Untitled",
                "file_type": document.file_type,
                "storage_mode": document.storage_mode,
                "has_blob": blob_size > 0,
                "blob_size": blob_size,
                "has_text": bool(document.text_content),
                "collections_count": len(collections),
                "chunks_count": total_chunks,
            }
