use axum::{
    extract::Request,
    middleware::Next,
    response::{IntoResponse, Response},
};
use reqwest::StatusCode;
use tower_sessions::Session;

use crate::infrastructure::auth::LOGGED_IN_USER_SESS_KEY;
use crate::infrastructure::state::UserStateInner;

/// Server function endpoints that are allowed without authentication.
///
/// `check-auth` must be public so the frontend can determine login state.
const PUBLIC_API_ENDPOINTS: &[&str] = &["/api/check-auth"];

/// Axum middleware that enforces authentication on `/api/` server
/// function endpoints.
///
/// Requests whose path starts with `/api/` (except those listed in
/// [`PUBLIC_API_ENDPOINTS`]) are rejected with `401 Unauthorized` when
/// no valid session exists. All other paths pass through untouched.
pub async fn require_auth(session: Session, request: Request, next: Next) -> Response {
    let path = request.uri().path();

    // Only gate /api/ server function routes.
    if path.starts_with("/api/") && !PUBLIC_API_ENDPOINTS.contains(&path) {
        let is_authed = session
            .get::<UserStateInner>(LOGGED_IN_USER_SESS_KEY)
            .await
            .ok()
            .flatten()
            .is_some();

        if !is_authed {
            return (StatusCode::UNAUTHORIZED, "Authentication required").into_response();
        }
    }

    next.run(request).await
}
