"""
Tests for web/auth/cleanup_middleware.py

Tests cover:
- cleanup_completed_research() function
- Research cleanup behavior
- Database error handling
"""

from unittest.mock import MagicMock, patch

import pytest
from flask import Flask


class TestCleanupCompletedResearch:
    """Tests for cleanup_completed_research function."""

    @pytest.fixture(autouse=True)
    def _bypass_random_gate(self):
        """Ensure the 1% random sampling gate always passes so tests
        exercise the actual cleanup logic."""
        with patch(
            "local_deep_research.web.auth.cleanup_middleware.random.randint",
            return_value=1,
        ):
            yield

    def test_skips_when_middleware_should_skip(self):
        """Should skip cleanup when should_skip_database_middleware returns True."""
        app = Flask(__name__)
        app.secret_key = "test"

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = True

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )

            with app.test_request_context("/static/app.js"):
                result = cleanup_completed_research()
                assert result is None

    def test_skips_when_no_username_in_session(self):
        """Should skip cleanup when no username in session."""
        app = Flask(__name__)
        app.secret_key = "test"

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )

            with app.test_request_context("/dashboard"):
                result = cleanup_completed_research()
                assert result is None

    def test_skips_when_no_db_session_in_g(self):
        """Should skip cleanup when no db_session in g."""
        app = Flask(__name__)
        app.secret_key = "test"

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                result = cleanup_completed_research()
                assert result is None

    def test_cleans_up_completed_research_records(self):
        """Should delete records for research not in active_research."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_record = MagicMock()
        mock_record.research_id = "completed_research_123"
        mock_db_session.query.return_value.filter_by.return_value.limit.return_value.all.return_value = [
            mock_record
        ]

        with (
            patch(
                "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.routes.globals.is_research_active",
                return_value=False,
            ),
        ):
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                cleanup_completed_research()

                # Verify delete was called
                mock_db_session.delete.assert_called_once_with(mock_record)
                mock_db_session.commit.assert_called_once()

    def test_does_not_clean_active_research(self):
        """Should not delete records for active research."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_record = MagicMock()
        mock_record.research_id = "active_research_456"
        mock_db_session.query.return_value.filter_by.return_value.limit.return_value.all.return_value = [
            mock_record
        ]

        with (
            patch(
                "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.routes.globals.is_research_active",
                return_value=True,
            ),
        ):
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                cleanup_completed_research()

                # Verify delete was NOT called
                mock_db_session.delete.assert_not_called()
                mock_db_session.commit.assert_not_called()

    def test_handles_operational_error(self):
        """Should handle OperationalError gracefully."""
        from sqlalchemy.exc import OperationalError

        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_db_session.query.side_effect = OperationalError("test", {}, None)

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                # Should not raise exception
                cleanup_completed_research()
                mock_db_session.rollback.assert_called()

    def test_handles_pending_rollback_error(self):
        """Should handle PendingRollbackError gracefully."""
        from sqlalchemy.exc import PendingRollbackError

        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_db_session.query.side_effect = PendingRollbackError(
            "pending rollback"
        )

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                # Should not raise exception
                cleanup_completed_research()
                mock_db_session.rollback.assert_called()

    def test_handles_timeout_error(self):
        """Should handle TimeoutError gracefully."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_db_session.query.side_effect = TimeoutError("test timeout")

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                # Should not raise exception
                cleanup_completed_research()
                mock_db_session.rollback.assert_called()

    def test_handles_generic_exception(self):
        """Should handle generic exceptions gracefully."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_db_session.query.side_effect = Exception("generic error")

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                # Should not raise exception
                cleanup_completed_research()
                mock_db_session.rollback.assert_called()

    def test_handles_rollback_failure(self):
        """Should handle rollback failure gracefully."""
        from sqlalchemy.exc import OperationalError

        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_db_session.query.side_effect = OperationalError("test", {}, None)
        mock_db_session.rollback.side_effect = Exception("rollback failed")

        with patch(
            "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
        ) as mock_skip:
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                # Should not raise exception even if rollback fails
                cleanup_completed_research()

    def test_limits_query_to_50_records(self):
        """Should limit query to 50 records."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()
        mock_limit = MagicMock()
        mock_db_session.query.return_value.filter_by.return_value.limit.return_value = mock_limit
        mock_limit.all.return_value = []

        with (
            patch(
                "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.routes.globals.is_research_active",
                return_value=False,
            ),
        ):
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                cleanup_completed_research()

                # Verify limit(50) was called
                mock_db_session.query.return_value.filter_by.return_value.limit.assert_called_with(
                    50
                )

    def test_skips_cleanup_on_random_sampling(self, _bypass_random_gate):
        """Should skip cleanup when random sampling doesn't select this request."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_db_session = MagicMock()

        with (
            patch(
                "local_deep_research.web.auth.cleanup_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.cleanup_middleware.random.randint",
                return_value=50,
            ),
        ):
            mock_skip.return_value = False

            from local_deep_research.web.auth.cleanup_middleware import (
                cleanup_completed_research,
            )
            from flask import session, g

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                g.db_session = mock_db_session

                result = cleanup_completed_research()

                assert result is None
                mock_db_session.query.assert_not_called()
