"""T-AZ-041 (explicit allowlist, default-deny), T-AZ-042 (no id-auth
reserved routes), T-AZ-045 (headers never grant identity)."""

from pathlib import Path

from fastapi.routing import APIRoute

from app.main import create_app

DIST_ASSETS = Path(__file__).resolve().parents[1] / "frontend" / "dist" / "assets"


# ---------------------------------------------------------------- T-AZ-041


def test_t_az_041_healthz_serves_without_session(client):
    resp = client.get("/healthz")
    assert resp.status_code == 200
    assert resp.json() == {"status": "ok"}
    # db-connected status stays OUT of the public health check.
    assert "db" not in resp.json()


def test_t_az_041_api_meta_requires_session(client):
    resp = client.get("/api/meta")
    assert resp.status_code == 401
    body = resp.json()
    assert body["error_code"] == "NOT_AUTHENTICATED"
    assert "summary" in body


def test_t_az_041_api_meta_serves_with_session(authed_client):
    assert authed_client.get("/api/meta").status_code == 200


def test_t_az_041_unknown_page_route_redirects_into_flow(client):
    resp = client.get("/some/deep/page?week=27", follow_redirects=False)
    assert resp.status_code == 302
    location = resp.headers["location"]
    assert location.startswith("/auth/login?next=")
    assert "%2Fsome%2Fdeep%2Fpage" in location


def test_t_az_041_root_redirects_when_unauthenticated(client):
    resp = client.get("/", follow_redirects=False)
    assert resp.status_code == 302
    assert resp.headers["location"].startswith("/auth/login")


def test_t_az_041_unknown_api_route_is_401_not_404(client):
    # Default-deny runs BEFORE routing: even a nonexistent /api path is 401.
    assert client.get("/api/nonexistent").status_code == 401


def test_t_az_041_static_assets_serve_without_session(client):
    bundles = sorted(DIST_ASSETS.glob("*.js")) if DIST_ASSETS.is_dir() else []
    assert bundles, "frontend/dist/assets must exist (vite build ships in-repo)"
    resp = client.get(f"/assets/{bundles[0].name}")
    assert resp.status_code == 200


def test_t_az_041_gate_responses_still_carry_version_header(client):
    # The skew banner depends on every response carrying the version —
    # including the auth gate's own 401s.
    resp = client.get("/api/meta")
    assert resp.status_code == 401
    assert resp.headers.get("x-with-version")


# ---------------------------------------------------------------- T-AZ-042


def _api_route_paths(app) -> set[str]:
    """Every APIRoute path, descending into included routers (FastAPI
    0.139 wraps include_router targets in _IncludedRouter)."""
    paths: set[str] = set()

    def walk(routes):
        for route in routes:
            if isinstance(route, APIRoute):
                paths.add(route.path)
            original = getattr(route, "original_router", None)
            if original is not None:
                walk(original.routes)

    walk(app.routes)
    return paths


def test_t_az_042_no_idauth_reserved_routes_defined():
    paths = _api_route_paths(create_app())
    assert paths, "route walk found nothing — walker broken?"
    assert not paths & {"/login", "/logout", "/authorize", "/_grant"}, (
        "id-auth's gate snippet owns /login /logout /authorize /_grant — "
        "the app must never define them (PATTERN-B.md §1b)"
    )
    auth_paths = {p for p in paths if p.startswith("/auth")}
    assert auth_paths == {"/auth/login", "/auth/callback", "/auth/logout"}


# ---------------------------------------------------------------- T-AZ-045


def test_t_az_045_identity_headers_never_grant(client):
    for headers in (
        {"X-Auth-User": "rian"},
        {"X_Auth_User": "rian"},
        {"x-auth-user": "rian", "X-Auth-Email": "rian@rian.ca"},
        {"X-Auth-User": "rian", "X-Auth-Grant": "super_admin"},
    ):
        assert client.get("/api/meta", headers=headers).status_code == 401
        assert client.get("/api/me", headers=headers).status_code == 401


def test_t_az_045_spoofed_header_does_not_override_session(authed_client, db_engine):
    resp = authed_client.get("/api/me", headers={"X-Auth-User": "mallory"})
    assert resp.status_code == 200
    assert resp.json()["username"] == "rian"  # session wins; header ignored
