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

Tests cover:
- ensure_user_database() function
- Password retrieval from various sources
- Database session setup via db_manager.open_user_database()
"""

from unittest.mock import MagicMock, patch

from flask import Flask


class TestEnsureUserDatabase:
    """Tests for ensure_user_database function."""

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

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

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )

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

    def test_skips_when_already_initialized(self):
        """Should skip when _db_initialized flag is already set."""
        app = Flask(__name__)
        app.secret_key = "test"

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

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import g

            with app.test_request_context("/dashboard"):
                g._db_initialized = True

                result = ensure_user_database()
                assert result is None

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

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

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )

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

    def test_retrieves_password_from_temp_auth_token(self):
        """Should retrieve password from temp auth token."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_temp_auth = MagicMock()
        mock_temp_auth.retrieve_auth.return_value = ("testuser", "password123")

        mock_session_password_store = MagicMock()

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
            patch(
                "local_deep_research.database.temp_auth.temp_auth_store",
                mock_temp_auth,
            ),
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_session_password_store,
            ),
        ):
            mock_skip.return_value = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                session["temp_auth_token"] = "test_token_123"
                session["session_id"] = "session_456"

                ensure_user_database()

                mock_temp_auth.retrieve_auth.assert_called_once_with(
                    "test_token_123"
                )

    def test_stores_password_in_session_password_store(self):
        """Should store password in session password store after temp auth."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_temp_auth = MagicMock()
        mock_temp_auth.retrieve_auth.return_value = ("testuser", "password123")

        mock_session_password_store = MagicMock()

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
            patch(
                "local_deep_research.database.temp_auth.temp_auth_store",
                mock_temp_auth,
            ),
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_session_password_store,
            ),
        ):
            mock_skip.return_value = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                session["temp_auth_token"] = "test_token_123"
                session["session_id"] = "session_456"

                ensure_user_database()

                mock_session_password_store.store_session_password.assert_called_once_with(
                    "testuser", "session_456", "password123"
                )

    def test_retrieves_password_from_session_password_store(self):
        """Should retrieve password from session password store."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_session_password_store = MagicMock()
        mock_session_password_store.get_session_password.return_value = (
            "stored_password"
        )

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_session_password_store,
            ),
        ):
            mock_skip.return_value = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                session["session_id"] = "session_456"

                ensure_user_database()

                mock_session_password_store.get_session_password.assert_called_with(
                    "testuser", "session_456"
                )

    def test_uses_dummy_password_for_unencrypted_db(self):
        """Should use dummy password for unencrypted database."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

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

                ensure_user_database()

                mock_db_manager.open_user_database.assert_called_with(
                    "testuser", "dummy"
                )

    def test_sets_db_initialized_flag(self):
        """Should set _db_initialized flag when database is opened."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import g, session

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

                ensure_user_database()

                assert g._db_initialized is True

    def test_sets_g_username(self):
        """Should set g.username."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = MagicMock()

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import g, session

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

                ensure_user_database()

                assert g.username == "testuser"

    def test_handles_exception_gracefully(self):
        """Should handle exceptions gracefully without raising."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.side_effect = Exception(
                "DB error"
            )

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

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

                # Should not raise exception
                ensure_user_database()

    def test_skips_temp_auth_if_username_mismatch(self):
        """Should skip temp auth if stored username doesn't match session."""
        app = Flask(__name__)
        app.secret_key = "test"

        mock_temp_auth = MagicMock()
        mock_temp_auth.retrieve_auth.return_value = (
            "different_user",
            "password123",
        )

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

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.database.temp_auth.temp_auth_store",
                mock_temp_auth,
            ),
            patch(
                "local_deep_research.database.session_passwords.session_password_store",
                mock_session_password_store,
            ),
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = True

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import session

            with app.test_request_context("/dashboard"):
                session["username"] = "testuser"
                session["temp_auth_token"] = "test_token_123"

                ensure_user_database()

                # Should not have stored password since username didn't match
                mock_session_password_store.store_session_password.assert_not_called()

    def test_skips_open_when_already_connected(self):
        """Should skip open_user_database when user is already connected."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.return_value = True

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import g, session

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

                ensure_user_database()

                mock_db_manager.open_user_database.assert_not_called()
                assert g._db_initialized is True

    def test_returns_when_open_user_database_returns_none(self):
        """Should return early when open_user_database returns None."""
        app = Flask(__name__)
        app.secret_key = "test"

        with (
            patch(
                "local_deep_research.web.auth.database_middleware.should_skip_database_middleware"
            ) as mock_skip,
            patch(
                "local_deep_research.web.auth.database_middleware.db_manager"
            ) as mock_db_manager,
        ):
            mock_skip.return_value = False
            mock_db_manager.has_encryption = False
            mock_db_manager.is_user_connected.return_value = False
            mock_db_manager.open_user_database.return_value = None

            from local_deep_research.web.auth.database_middleware import (
                ensure_user_database,
            )
            from flask import g, session

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

                ensure_user_database()

                assert not getattr(g, "_db_initialized", False)
