"""
Coverage tests for delete_routes.py focusing on untested logic branches.

Covers:
- delete_document_blob: not found (404), other error (400), exception (500)
- Bulk endpoint validation across documents/blobs/collections/preview:
  null body, missing key, string IDs, empty list
- Exception handling for document/collection/index/remove-from-collection
- Preview not-found paths for both document and collection endpoints

Source: src/local_deep_research/research_library/deletion/routes/delete_routes.py
"""

from contextlib import contextmanager
from unittest.mock import Mock, patch

from flask import Flask, jsonify

from local_deep_research.research_library.deletion.routes.delete_routes import (
    delete_bp,
)
from local_deep_research.web.auth.routes import auth_bp

_ROUTES_MOD = (
    "local_deep_research.research_library.deletion.routes.delete_routes"
)


def _create_app():
    app = Flask(__name__)
    app.config["SECRET_KEY"] = "test-secret"
    app.config["WTF_CSRF_ENABLED"] = False
    app.register_blueprint(auth_bp)
    app.register_blueprint(delete_bp)

    @app.errorhandler(500)
    def _handle_500(error):
        return jsonify({"error": "Internal server error"}), 500

    return app


@contextmanager
def _auth_client(app, doc_svc=None, coll_svc=None, bulk_svc=None):
    """Provide an authenticated Flask test client with mocked services."""
    mock_db = Mock()
    mock_db.connections = {"testuser": True}
    mock_db.has_encryption = False

    patches = [
        patch("local_deep_research.web.auth.decorators.db_manager", mock_db),
        patch(
            f"{_ROUTES_MOD}.DocumentDeletionService",
            Mock(return_value=doc_svc or Mock()),
        ),
        patch(
            f"{_ROUTES_MOD}.CollectionDeletionService",
            Mock(return_value=coll_svc or Mock()),
        ),
        patch(
            f"{_ROUTES_MOD}.BulkDeletionService",
            Mock(return_value=bulk_svc or Mock()),
        ),
    ]

    started = []
    try:
        for p in patches:
            started.append(p.start())
        with app.test_client() as client:
            with client.session_transaction() as sess:
                sess["username"] = "testuser"
                sess["session_id"] = "test-session-id"
            yield client
    finally:
        for p in patches:
            p.stop()


class TestDeleteDocumentBlobBranches:
    """Cover all three return paths in delete_document_blob."""

    def test_not_found_returns_404(self):
        app = _create_app()
        svc = Mock()
        svc.delete_blob_only.return_value = {
            "deleted": False,
            "error": "Document not found",
        }
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 404
            data = resp.get_json()
            assert data["success"] is False

    def test_other_error_returns_400(self):
        app = _create_app()
        svc = Mock()
        svc.delete_blob_only.return_value = {
            "deleted": False,
            "error": "No blob attached",
        }
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 400
            data = resp.get_json()
            assert data["success"] is False

    def test_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_blob_only.side_effect = RuntimeError("disk failure")
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 500


class TestBulkDocumentsValidation:
    """Validation paths for DELETE /library/api/documents/bulk."""

    def test_no_body_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                content_type="application/json",
                data="null",
            )
            assert resp.status_code == 400
            assert "document_ids required" in resp.get_json()["error"]

    def test_missing_key_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk", json={"ids": ["a"]}
            )
            assert resp.status_code == 400

    def test_string_ids_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                json={"document_ids": "not-a-list"},
            )
            assert resp.status_code == 400
            assert "non-empty list" in resp.get_json()["error"]

    def test_empty_list_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk", json={"document_ids": []}
            )
            assert resp.status_code == 400
            assert "non-empty list" in resp.get_json()["error"]

    def test_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_documents.side_effect = RuntimeError("boom")
        with _auth_client(app, bulk_svc=svc) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                json={"document_ids": ["d1"]},
            )
            assert resp.status_code == 500


class TestBulkBlobsValidation:
    """Validation paths for DELETE /library/api/documents/blobs."""

    def test_no_body_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/blobs",
                content_type="application/json",
                data="null",
            )
            assert resp.status_code == 400

    def test_missing_key_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete("/library/api/documents/blobs", json={})
            assert resp.status_code == 400

    def test_string_ids_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/blobs",
                json={"document_ids": "single-string"},
            )
            assert resp.status_code == 400

    def test_empty_list_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/documents/blobs", json={"document_ids": []}
            )
            assert resp.status_code == 400

    def test_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_blobs.side_effect = RuntimeError("boom")
        with _auth_client(app, bulk_svc=svc) as client:
            resp = client.delete(
                "/library/api/documents/blobs",
                json={"document_ids": ["d1"]},
            )
            assert resp.status_code == 500


class TestBulkCollectionValidation:
    """Validation paths for DELETE /collection/<id>/documents/bulk."""

    def test_no_body_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                content_type="application/json",
                data="null",
            )
            assert resp.status_code == 400

    def test_string_ids_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                json={"document_ids": "oops"},
            )
            assert resp.status_code == 400

    def test_empty_list_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                json={"document_ids": []},
            )
            assert resp.status_code == 400

    def test_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.remove_documents_from_collection.side_effect = RuntimeError("boom")
        with _auth_client(app, bulk_svc=svc) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                json={"document_ids": ["d1"]},
            )
            assert resp.status_code == 500


class TestBulkPreviewValidation:
    """Validation paths for POST /library/api/documents/preview."""

    def test_no_body_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.post(
                "/library/api/documents/preview",
                content_type="application/json",
                data="null",
            )
            assert resp.status_code == 400

    def test_missing_key_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={"operation": "delete"},
            )
            assert resp.status_code == 400

    def test_string_ids_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={"document_ids": "not-list"},
            )
            assert resp.status_code == 400

    def test_empty_list_returns_400(self):
        app = _create_app()
        with _auth_client(app) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={"document_ids": []},
            )
            assert resp.status_code == 400

    def test_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.get_bulk_preview.side_effect = RuntimeError("boom")
        with _auth_client(app, bulk_svc=svc) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={"document_ids": ["d1"]},
            )
            assert resp.status_code == 500


class TestExceptionPaths:
    """Service exceptions must be caught and return 500."""

    def test_delete_document_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_document.side_effect = RuntimeError("db crash")
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.delete("/library/api/document/doc-1")
            assert resp.status_code == 500

    def test_delete_collection_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_collection.side_effect = RuntimeError("db crash")
        with _auth_client(app, coll_svc=svc) as client:
            resp = client.delete("/library/api/collections/coll-1")
            assert resp.status_code == 500

    def test_delete_collection_index_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.delete_collection_index_only.side_effect = RuntimeError("db crash")
        with _auth_client(app, coll_svc=svc) as client:
            resp = client.delete("/library/api/collections/coll-1/index")
            assert resp.status_code == 500

    def test_remove_from_collection_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.remove_from_collection.side_effect = RuntimeError("db crash")
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/document/doc-1"
            )
            assert resp.status_code == 500


class TestPreviewNotFound:
    """Preview endpoints return 404 when resource is not found."""

    def test_document_preview_not_found_returns_404(self):
        app = _create_app()
        svc = Mock()
        svc.get_deletion_preview.return_value = {"found": False}
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.get("/library/api/document/doc-missing/preview")
            assert resp.status_code == 404
            data = resp.get_json()
            assert data["success"] is False
            assert data["error"] == "Document not found"

    def test_collection_preview_not_found_returns_404(self):
        app = _create_app()
        svc = Mock()
        svc.get_deletion_preview.return_value = {"found": False}
        with _auth_client(app, coll_svc=svc) as client:
            resp = client.get("/library/api/collections/coll-missing/preview")
            assert resp.status_code == 404
            data = resp.get_json()
            assert data["success"] is False
            assert data["error"] == "Collection not found"

    def test_document_preview_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.get_deletion_preview.side_effect = RuntimeError("boom")
        with _auth_client(app, doc_svc=svc) as client:
            resp = client.get("/library/api/document/doc-1/preview")
            assert resp.status_code == 500

    def test_collection_preview_exception_returns_500(self):
        app = _create_app()
        svc = Mock()
        svc.get_deletion_preview.side_effect = RuntimeError("boom")
        with _auth_client(app, coll_svc=svc) as client:
            resp = client.get("/library/api/collections/coll-1/preview")
            assert resp.status_code == 500
