"""Coverage tests for web/auth/decorators.py — untested branches."""

from unittest.mock import MagicMock, patch

import pytest
from flask import Flask

MODULE = "local_deep_research.web.auth.decorators"


@pytest.fixture()
def app():
    flask_app = Flask(__name__)
    flask_app.secret_key = "test-secret"
    flask_app.config["TESTING"] = True

    # Register a fake auth.login endpoint for redirect tests
    @flask_app.route("/auth/login")
    def login():
        return "login page"

    # Register protected routes using the real decorator
    from local_deep_research.web.auth.decorators import login_required

    @flask_app.route("/page")
    @login_required
    def page():
        return "ok"

    @flask_app.route("/api/data")
    @login_required
    def api_data():
        return "ok"

    @flask_app.route("/settings/api/config")
    @login_required
    def settings_api():
        return "ok"

    return flask_app


@pytest.fixture()
def client(app):
    return app.test_client()


# ---------------------------------------------------------------------------
# login_required — unauthenticated
# ---------------------------------------------------------------------------


class TestLoginRequiredUnauthenticated:
    def test_api_returns_401_json(self, client):
        with patch(f"{MODULE}.db_manager"):
            resp = client.get("/api/data")
        assert resp.status_code == 401
        assert resp.get_json()["error"] == "Authentication required"

    def test_settings_api_returns_401_json(self, client):
        with patch(f"{MODULE}.db_manager"):
            resp = client.get("/settings/api/config")
        assert resp.status_code == 401

    def test_page_calls_safe_redirect(self, client):
        """Non-API route triggers _safe_redirect_to_login."""
        with (
            patch(f"{MODULE}.db_manager"),
            patch(
                f"{MODULE}._safe_redirect_to_login",
                return_value=("redirected", 302),
            ) as mock_redirect,
        ):
            client.get("/page")
        mock_redirect.assert_called_once()


# ---------------------------------------------------------------------------
# login_required — no db connection
# ---------------------------------------------------------------------------


class TestLoginRequiredNoDbConnection:
    def test_api_returns_401_on_no_db(self, app, client):
        with patch(f"{MODULE}.db_manager") as mock_db:
            mock_db.is_user_connected.return_value = False

            with client.session_transaction() as sess:
                sess["username"] = "testuser"

            resp = client.get("/api/data")

        assert resp.status_code == 401
        assert "Database connection" in resp.get_json()["error"]

    def test_page_clears_session_on_no_db(self, app, client):
        with (
            patch(f"{MODULE}.db_manager") as mock_db,
            patch(
                f"{MODULE}._safe_redirect_to_login",
                return_value=("redirected", 302),
            ),
        ):
            mock_db.is_user_connected.return_value = False

            with client.session_transaction() as sess:
                sess["username"] = "testuser"

            client.get("/page")


# ---------------------------------------------------------------------------
# login_required — authenticated with db
# ---------------------------------------------------------------------------


class TestLoginRequiredAuthenticated:
    def test_page_succeeds(self, client):
        with patch(f"{MODULE}.db_manager") as mock_db:
            mock_db.is_user_connected.return_value = True

            with client.session_transaction() as sess:
                sess["username"] = "testuser"

            resp = client.get("/page")

        assert resp.status_code == 200


# ---------------------------------------------------------------------------
# inject_current_user
# ---------------------------------------------------------------------------


class TestInjectCurrentUser:
    def test_no_user_sets_none(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        with (
            app.test_request_context("/"),
            patch(f"{MODULE}.db_manager"),
        ):
            from flask import g

            inject_current_user()

            assert g.current_user is None
            assert g.db_session is None

    def test_connected_user_sets_session(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        mock_session = MagicMock()
        with (
            app.test_request_context("/"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.is_user_connected.return_value = True
            mock_db.get_session.return_value = mock_session
            from flask import g, session

            session["username"] = "testuser"

            inject_current_user()

            assert g.current_user == "testuser"
            assert g.db_session is mock_session

    def test_disconnected_user_on_api_route(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        with (
            app.test_request_context("/api/data"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            from flask import g, session

            session["username"] = "testuser"

            inject_current_user()

            # API route: user preserved but db_session is None
            assert g.current_user == "testuser"
            assert g.db_session is None

    def test_disconnected_user_on_page_clears_session(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        with (
            app.test_request_context("/page"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            from flask import g, session

            session["username"] = "testuser"

            inject_current_user()

            assert g.current_user is None
            assert g.db_session is None

    def test_get_session_exception_sets_none(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        with (
            app.test_request_context("/"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.is_user_connected.return_value = True
            mock_db.get_session.side_effect = RuntimeError("db error")
            from flask import g, session

            session["username"] = "testuser"

            inject_current_user()

            assert g.current_user == "testuser"
            assert g.db_session is None

    def test_auth_route_allows_disconnected(self, app):
        from local_deep_research.web.auth.decorators import inject_current_user

        with (
            app.test_request_context("/auth/login"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.is_user_connected.return_value = False
            from flask import g, session

            session["username"] = "testuser"

            inject_current_user()

            # Auth route: user preserved
            assert g.current_user == "testuser"


# ---------------------------------------------------------------------------
# current_user / get_current_db_session
# ---------------------------------------------------------------------------


class TestCurrentUser:
    def test_returns_username(self, app):
        from local_deep_research.web.auth.decorators import current_user

        with app.test_request_context("/"):
            from flask import session

            session["username"] = "alice"
            assert current_user() == "alice"

    def test_returns_none_when_not_set(self, app):
        from local_deep_research.web.auth.decorators import current_user

        with app.test_request_context("/"):
            assert current_user() is None


class TestGetCurrentDbSession:
    def test_returns_session(self, app):
        from local_deep_research.web.auth.decorators import (
            get_current_db_session,
        )

        mock_sess = MagicMock()
        with (
            app.test_request_context("/"),
            patch(f"{MODULE}.db_manager") as mock_db,
        ):
            mock_db.get_session.return_value = mock_sess
            from flask import session

            session["username"] = "alice"

            result = get_current_db_session()
            assert result is mock_sess

    def test_returns_none_when_no_user(self, app):
        from local_deep_research.web.auth.decorators import (
            get_current_db_session,
        )

        with app.test_request_context("/"):
            assert get_current_db_session() is None
