"""Tests for ``mgf.common.fastapi`` Depends helpers."""

from __future__ import annotations

from typing import Any

from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from mgf.common.exceptions import AppConfigError

from mgf.fastapi import (
    ExceptionTranslationMiddleware,
    RequestIdMiddleware,
    get_app_context,
    get_request_id,
    get_settings,
    setup_lifespan,
)


class TestGetAppContext:
    def test_returns_context_when_lifespan_active(self) -> None:
        app = FastAPI(
            lifespan=setup_lifespan(app_name="test-app", app_version="0.0.1"),
        )

        @app.get("/whoami")
        def _whoami(ctx: Any = Depends(get_app_context)) -> dict[str, str]:
            return {"app": ctx.app_name}

        with TestClient(app) as client:
            response = client.get("/whoami")
        assert response.status_code == 200
        assert response.json()["app"] == "test-app"

    def test_raises_appconfigerror_when_lifespan_missing(self) -> None:
        # No setup_lifespan — ExceptionTranslationMiddleware catches
        # the AppConfigError and returns 500.
        app = FastAPI()
        app.add_middleware(ExceptionTranslationMiddleware)

        @app.get("/whoami")
        def _whoami(ctx: Any = Depends(get_app_context)) -> dict[str, str]:
            return {"app": ctx.app_name}

        with TestClient(app) as client:
            response = client.get("/whoami")
        assert response.status_code == 500
        body = response.json()
        assert body["error"]["type"] == "AppConfigError"
        assert "lifespan" in body["error"]["message"].lower()

    def test_raises_appconfigerror_directly_outside_middleware(self) -> None:
        # Without translation middleware, FastAPI's default behavior
        # surfaces the exception. Just verify the response is 500.
        app = FastAPI()  # no lifespan

        @app.get("/whoami")
        def _whoami(ctx: Any = Depends(get_app_context)) -> dict[str, str]:
            return {"app": ctx.app_name}

        with TestClient(app, raise_server_exceptions=False) as client:
            response = client.get("/whoami")
        assert response.status_code == 500


class TestGetSettings:
    def test_returns_settings_attached_to_context(self) -> None:
        app = FastAPI(
            lifespan=setup_lifespan(app_name="test-app", app_version="0.0.1"),
        )

        @app.get("/log-level")
        def _log_level(s: Any = Depends(get_settings)) -> dict[str, str]:
            return {"level": s.logging.level}

        with TestClient(app) as client:
            response = client.get("/log-level")
        assert response.status_code == 200
        # Default-bootstrap level is INFO unless overridden.
        assert response.json()["level"] in {"DEBUG", "INFO", "WARNING", "ERROR"}


class TestGetRequestId:
    def test_returns_id_when_middleware_present(self) -> None:
        app = FastAPI()
        app.add_middleware(RequestIdMiddleware)

        @app.get("/rid")
        def _rid(rid: str = Depends(get_request_id)) -> dict[str, str]:
            return {"rid": rid}

        with TestClient(app) as client:
            response = client.get(
                "/rid",
                headers={"X-Request-Id": "from-test-001"},
            )
        assert response.json()["rid"] == "from-test-001"

    def test_returns_empty_string_when_middleware_absent(self) -> None:
        app = FastAPI()  # no middleware

        @app.get("/rid")
        def _rid(rid: str = Depends(get_request_id)) -> dict[str, str]:
            return {"rid": rid}

        with TestClient(app) as client:
            response = client.get("/rid")
        assert response.status_code == 200
        assert response.json()["rid"] == ""


class TestFullStack:
    """Smoke test combining lifespan + both middlewares + dependencies."""

    def test_full_stack_works(self) -> None:
        app = FastAPI(
            lifespan=setup_lifespan(app_name="full", app_version="1.0.0"),
        )
        app.add_middleware(ExceptionTranslationMiddleware)
        app.add_middleware(RequestIdMiddleware)

        @app.get("/ok")
        def _ok(
            ctx: Any = Depends(get_app_context),
            rid: str = Depends(get_request_id),
        ) -> dict[str, str]:
            return {"app": ctx.app_name, "request_id": rid}

        @app.get("/fail")
        def _fail() -> dict[str, str]:
            raise AppConfigError("intentional")

        with TestClient(app) as client:
            ok_response = client.get("/ok")
            assert ok_response.status_code == 200
            assert ok_response.json()["app"] == "full"
            assert len(ok_response.json()["request_id"]) > 0

            fail_response = client.get(
                "/fail",
                headers={"X-Request-Id": "test-failure-trace"},
            )
            assert fail_response.status_code == 500
            assert fail_response.json()["error"]["type"] == "AppConfigError"
            assert fail_response.json()["error"]["request_id"] == "test-failure-trace"
