"""Tests for Flask middleware and decorators."""

from unittest.mock import patch

import pytest
from flask import Flask

from conduit_auth import AuthSettings
from conduit_auth.flask import get_current_user, init_auth, require_auth


def _create_app(settings: AuthSettings) -> Flask:
    """Create a test Flask app with auth middleware."""
    app = Flask(__name__)
    app.config["TESTING"] = True
    init_auth(app, settings)

    @app.route("/api/protected")
    def protected():
        user = get_current_user()
        return {
            "tenant_id": user.tenant_id,
            "user_id": user.user_id,
            "email": user.email,
            "display_name": user.display_name,
        }

    @app.route("/api/decorated")
    @require_auth
    def decorated():
        user = get_current_user()
        return {"email": user.email}

    @app.route("/health")
    def health():
        return {"status": "ok"}

    @app.route("/not-api")
    def not_api():
        return {"message": "public"}

    return app


class TestFlaskMiddleware:
    def test_missing_auth_header(self, auth_settings):
        app = _create_app(auth_settings)
        with app.test_client() as client:
            resp = client.get("/api/protected")

        assert resp.status_code == 401
        assert "Authorization" in resp.json["error"]

    def test_valid_token(self, auth_settings, make_token, jwks_keys):
        app = _create_app(auth_settings)
        token = make_token()

        with patch("conduit_auth.flask.middleware.get_key_cache") as mock_cache:
            mock_cache.return_value.get_keys.return_value = jwks_keys
            with app.test_client() as client:
                resp = client.get(
                    "/api/protected",
                    headers={"Authorization": f"Bearer {token}"},
                )

        assert resp.status_code == 200
        assert resp.json["email"] == "user@example.com"
        assert resp.json["tenant_id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

    def test_expired_token(self, auth_settings, make_token, jwks_keys):
        app = _create_app(auth_settings)
        token = make_token(expired=True)

        with patch("conduit_auth.flask.middleware.get_key_cache") as mock_cache:
            mock_cache.return_value.get_keys.return_value = jwks_keys
            with app.test_client() as client:
                resp = client.get(
                    "/api/protected",
                    headers={"Authorization": f"Bearer {token}"},
                )

        assert resp.status_code == 401
        assert "expired" in resp.json["error"]

    def test_health_excluded(self, auth_settings):
        app = _create_app(auth_settings)
        with app.test_client() as client:
            resp = client.get("/health")

        assert resp.status_code == 200

    def test_non_api_path_excluded(self, auth_settings):
        app = _create_app(auth_settings)
        with app.test_client() as client:
            resp = client.get("/not-api")

        assert resp.status_code == 200

    def test_auth_disabled(self, test_client_id):
        settings = AuthSettings(
            ENTRA_CLIENT_ID=test_client_id, AUTH_DISABLED=True
        )
        app = _create_app(settings)
        with app.test_client() as client:
            resp = client.get("/api/protected")

        assert resp.status_code == 200
        assert resp.json["email"] == "dev@localhost"

    def test_require_auth_decorator(self, auth_settings, make_token, jwks_keys):
        app = _create_app(auth_settings)
        token = make_token()

        with patch("conduit_auth.flask.middleware.get_key_cache") as mock_cache:
            mock_cache.return_value.get_keys.return_value = jwks_keys
            with app.test_client() as client:
                resp = client.get(
                    "/api/decorated",
                    headers={"Authorization": f"Bearer {token}"},
                )

        assert resp.status_code == 200
        assert resp.json["email"] == "user@example.com"
