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

Tests cover:
- cleanup_stale_sessions() function
- Skip conditions (should_skip, no username, user connected, temp_auth_token, no encryption)
- Session clearing behavior (no session_id, session_id with no password, session_id with password)
"""

from unittest.mock import MagicMock, patch

from flask import Flask, session


def _make_app():
    """Create a minimal Flask test app with a secret key."""
    app = Flask(__name__)
    app.secret_key = "test-secret-key"
    return app


class TestCleanupStaleSessions:
    """Tests for cleanup_stale_sessions function."""

    def test_skips_when_should_skip_returns_true(self):
        """Should return immediately when should_skip_session_cleanup() is True."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=True,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                cleanup_stale_sessions()
                # db_manager should never be consulted
                mock_db.is_user_connected.assert_not_called()
                # Session should remain intact
                assert session.get("username") == "testuser"

    def test_does_nothing_when_no_username_in_session(self):
        """Should do nothing when session has no username."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                # No username set in session
                cleanup_stale_sessions()
                mock_db.is_user_connected.assert_not_called()

    def test_does_nothing_when_user_is_connected(self):
        """Should do nothing when db_manager.is_user_connected returns True."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            mock_db.is_user_connected.return_value = True

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                cleanup_stale_sessions()
                # Session should remain intact
                assert session.get("username") == "testuser"

    def test_does_nothing_when_temp_auth_token_exists(self):
        """Should not clear session when temp_auth_token is present (recovery possible)."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            mock_db.has_encryption = True

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                session["temp_auth_token"] = "some-recovery-token"
                cleanup_stale_sessions()
                # Session should remain intact
                assert session.get("username") == "testuser"

    def test_does_nothing_when_db_has_no_encryption(self):
        """Should not clear session when db_manager.has_encryption is False."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            mock_db.has_encryption = False

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                cleanup_stale_sessions()
                # Session should remain intact because encryption is off
                assert session.get("username") == "testuser"

    def test_clears_session_when_no_session_id_and_no_recovery(self):
        """Should clear session when there is no session_id (no way to recover)."""
        app = _make_app()

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            mock_db.has_encryption = True

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                # No session_id, no temp_auth_token
                cleanup_stale_sessions()
                # Session should be cleared
                assert session.get("username") is None

    def test_clears_session_when_session_id_but_no_password_in_store(self):
        """Should clear session when session_id exists but password store has no password."""
        app = _make_app()

        mock_password_store = MagicMock()
        mock_password_store.get_session_password.return_value = None

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_password_store,
            ),
        ):
            mock_db.is_user_connected.return_value = False
            mock_db.has_encryption = True

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                session["session_id"] = "sess-abc-123"
                cleanup_stale_sessions()
                # Session should be cleared
                assert session.get("username") is None
                mock_password_store.get_session_password.assert_called_once_with(
                    "testuser", "sess-abc-123"
                )

    def test_does_not_clear_session_when_password_found_in_store(self):
        """Should NOT clear session when password IS found in the session password store."""
        app = _make_app()

        mock_password_store = MagicMock()
        mock_password_store.get_session_password.return_value = (
            "stored-password"
        )

        with (
            patch(
                "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
                return_value=False,
            ),
            patch(
                "local_deep_research.web.auth.session_cleanup.db_manager"
            ) as mock_db,
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_password_store,
            ),
        ):
            mock_db.is_user_connected.return_value = False
            mock_db.has_encryption = True

            from local_deep_research.web.auth.session_cleanup import (
                cleanup_stale_sessions,
            )

            with app.test_request_context("/"):
                session["username"] = "testuser"
                session["session_id"] = "sess-abc-123"
                cleanup_stale_sessions()
                # Session should remain intact
                assert session.get("username") == "testuser"
                assert session.get("session_id") == "sess-abc-123"
                mock_password_store.get_session_password.assert_called_once_with(
                    "testuser", "sess-abc-123"
                )
