"""
HTTP integration tests for delete API endpoints.

42 existing tests mock services directly — zero client.delete() calls.
This file tests all 11 endpoints via Flask test client.

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.web.auth.routes import auth_bp
from local_deep_research.research_library.deletion.routes.delete_routes import (
    delete_bp,
)


# ---------------------------------------------------------------------------
# Test Infrastructure
# ---------------------------------------------------------------------------


def _create_test_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 _authenticated_client(
    app, mock_doc_service=None, mock_coll_service=None, mock_bulk_service=None
):
    """Context manager providing authenticated test client with mocked services."""
    mock_db = Mock()
    mock_db.connections = {"testuser": True}
    mock_db.has_encryption = False

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

    mock_doc_cls = Mock(return_value=mock_doc_service or Mock())
    mock_coll_cls = Mock(return_value=mock_coll_service or Mock())
    mock_bulk_cls = Mock(return_value=mock_bulk_service or Mock())

    patches = [
        patch("local_deep_research.web.auth.decorators.db_manager", mock_db),
        patch(f"{_routes_mod}.DocumentDeletionService", mock_doc_cls),
        patch(f"{_routes_mod}.CollectionDeletionService", mock_coll_cls),
        patch(f"{_routes_mod}.BulkDeletionService", mock_bulk_cls),
    ]

    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()


# ---------------------------------------------------------------------------
# DELETE /library/api/document/<id>
# ---------------------------------------------------------------------------


class TestDeleteDocument:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_document.return_value = {
            "deleted": True,
            "chunks_deleted": 5,
        }
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-1")
            assert resp.status_code == 200
            data = resp.get_json()
            assert data["success"] is True

    def test_not_found_returns_404(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_document.return_value = {
            "deleted": False,
            "error": "Not found",
        }
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-missing")
            assert resp.status_code == 404
            data = resp.get_json()
            assert data["success"] is False

    def test_exception_returns_500(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_document.side_effect = RuntimeError("DB error")
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-1")
            assert resp.status_code == 500


# ---------------------------------------------------------------------------
# DELETE /library/api/document/<id>/blob
# ---------------------------------------------------------------------------


class TestDeleteDocumentBlob:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_blob_only.return_value = {
            "deleted": True,
            "bytes_freed": 1024,
        }
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 200

    def test_not_found_returns_404(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_blob_only.return_value = {
            "deleted": False,
            "error": "Document not found",
        }
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 404

    def test_no_blob_returns_400(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_blob_only.return_value = {
            "deleted": False,
            "error": "No blob attached",
        }
        with _authenticated_client(app, mock_doc_service=svc) as client:
            resp = client.delete("/library/api/document/doc-1/blob")
            assert resp.status_code == 400


# ---------------------------------------------------------------------------
# DELETE /library/api/documents/bulk
# ---------------------------------------------------------------------------


class TestBulkDeleteDocuments:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_documents.return_value = {"deleted_count": 3}
        with _authenticated_client(app, mock_bulk_service=svc) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                json={"document_ids": ["d1", "d2", "d3"]},
            )
            assert resp.status_code == 200
            assert resp.get_json()["success"] is True

    def test_missing_document_ids_returns_400(self):
        app = _create_test_app()
        with _authenticated_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                json={"wrong_key": []},
            )
            assert resp.status_code == 400
            assert "document_ids required" in resp.get_json()["error"]

    def test_empty_list_returns_400(self):
        app = _create_test_app()
        with _authenticated_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_non_list_returns_400(self):
        app = _create_test_app()
        with _authenticated_client(app) as client:
            resp = client.delete(
                "/library/api/documents/bulk",
                json={"document_ids": "not-a-list"},
            )
            assert resp.status_code == 400


# ---------------------------------------------------------------------------
# DELETE /library/api/documents/blobs
# ---------------------------------------------------------------------------


class TestBulkDeleteBlobs:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_blobs.return_value = {"deleted_count": 2}
        with _authenticated_client(app, mock_bulk_service=svc) as client:
            resp = client.delete(
                "/library/api/documents/blobs",
                json={"document_ids": ["d1", "d2"]},
            )
            assert resp.status_code == 200

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

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


# ---------------------------------------------------------------------------
# DELETE /library/api/collection/<cid>/documents/bulk
# ---------------------------------------------------------------------------


class TestBulkRemoveFromCollection:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.remove_documents_from_collection.return_value = {"removed_count": 2}
        with _authenticated_client(app, mock_bulk_service=svc) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                json={"document_ids": ["d1", "d2"]},
            )
            assert resp.status_code == 200

    def test_missing_ids_returns_400(self):
        app = _create_test_app()
        with _authenticated_client(app) as client:
            resp = client.delete(
                "/library/api/collection/coll-1/documents/bulk",
                json={},
            )
            assert resp.status_code == 400


# ---------------------------------------------------------------------------
# POST /library/api/documents/preview
# ---------------------------------------------------------------------------


class TestBulkDeletionPreview:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.get_bulk_preview.return_value = {"total_size": 5000}
        with _authenticated_client(app, mock_bulk_service=svc) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={"document_ids": ["d1"]},
            )
            assert resp.status_code == 200
            assert resp.get_json()["success"] is True

    def test_missing_ids_returns_400(self):
        app = _create_test_app()
        with _authenticated_client(app) as client:
            resp = client.post(
                "/library/api/documents/preview",
                json={},
            )
            assert resp.status_code == 400


# ---------------------------------------------------------------------------
# DELETE /library/api/collections/<id>
# ---------------------------------------------------------------------------


class TestDeleteCollection:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_collection.return_value = {"deleted": True}
        with _authenticated_client(app, mock_coll_service=svc) as client:
            resp = client.delete("/library/api/collections/coll-1")
            assert resp.status_code == 200

    def test_not_found_returns_404(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_collection.return_value = {
            "deleted": False,
            "error": "Not found",
        }
        with _authenticated_client(app, mock_coll_service=svc) as client:
            resp = client.delete("/library/api/collections/coll-missing")
            assert resp.status_code == 404

    def test_generic_error_returns_400(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_collection.return_value = {
            "deleted": False,
            "error": "Cannot delete default collection",
        }
        with _authenticated_client(app, mock_coll_service=svc) as client:
            resp = client.delete("/library/api/collections/coll-1")
            assert resp.status_code == 400
            data = resp.get_json()
            assert data["success"] is False


# ---------------------------------------------------------------------------
# DELETE /library/api/collections/<id>/index
# ---------------------------------------------------------------------------


class TestDeleteCollectionIndex:
    def test_success_returns_200(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_collection_index_only.return_value = {"deleted": True}
        with _authenticated_client(app, mock_coll_service=svc) as client:
            resp = client.delete("/library/api/collections/coll-1/index")
            assert resp.status_code == 200

    def test_not_found_returns_404(self):
        app = _create_test_app()
        svc = Mock()
        svc.delete_collection_index_only.return_value = {
            "deleted": False,
            "error": "Not found",
        }
        with _authenticated_client(app, mock_coll_service=svc) as client:
            resp = client.delete("/library/api/collections/coll-missing/index")
            assert resp.status_code == 404


# ---------------------------------------------------------------------------
# Unauthenticated requests
# ---------------------------------------------------------------------------


class TestUnauthenticatedRequests:
    """All endpoints redirect (302) for unauthenticated requests.

    Note: /library/api/* paths do NOT start with /api/ so the login_required
    decorator redirects (302) instead of returning 401.
    """

    def test_delete_document_unauthenticated(self):
        app = _create_test_app()
        mock_db = Mock()
        mock_db.connections = {}
        mock_db.has_encryption = False
        with patch(
            "local_deep_research.web.auth.decorators.db_manager", mock_db
        ):
            with app.test_client() as client:
                resp = client.delete("/library/api/document/doc-1")
                assert resp.status_code == 302

    def test_delete_collection_unauthenticated(self):
        app = _create_test_app()
        mock_db = Mock()
        mock_db.connections = {}
        mock_db.has_encryption = False
        with patch(
            "local_deep_research.web.auth.decorators.db_manager", mock_db
        ):
            with app.test_client() as client:
                resp = client.delete("/library/api/collections/coll-1")
                assert resp.status_code == 302

    def test_bulk_delete_unauthenticated(self):
        app = _create_test_app()
        mock_db = Mock()
        mock_db.connections = {}
        mock_db.has_encryption = False
        with patch(
            "local_deep_research.web.auth.decorators.db_manager", mock_db
        ):
            with app.test_client() as client:
                resp = client.delete(
                    "/library/api/documents/bulk",
                    json={"document_ids": ["d1"]},
                )
                assert resp.status_code == 302
