/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use super::A;
use crate::ui::error::MyError;
use anyhow::anyhow;
use jellylogic::session::{bypass_auth_session, token_to_session, Session};
use log::warn;
use rocket::{
    async_trait,
    http::Status,
    outcome::Outcome,
    request::{self, FromRequest},
    Request,
};

pub(super) async fn session_from_request(req: &Request<'_>) -> Result<Session, MyError> {
    if cfg!(feature = "bypass-auth") {
        Ok(bypass_auth_session()?)
    } else {
        let token = req
            .query_value("session")
            .map(|e| e.unwrap())
            .or_else(|| req.query_value("api_key").map(|e| e.unwrap()))
            .or_else(|| req.headers().get_one("X-MediaBrowser-Token"))
            .or_else(|| {
                req.headers()
                    .get_one("Authorization")
                    .and_then(parse_jellyfin_auth)
            }) // for jellyfin compat
            .or(req.cookies().get("session").map(|cookie| cookie.value()))
            .ok_or(anyhow!("not logged in"))?;

        // jellyfin urlescapes the token for *some* requests
        let token = token.replace("%3D", "=");
        Ok(token_to_session(&token)?)
    }
}

fn parse_jellyfin_auth(h: &str) -> Option<&str> {
    for tok in h.split(" ") {
        if let Some(tok) = tok.strip_prefix("Token=\"") {
            if let Some(tok) = tok.strip_suffix("\"") {
                return Some(tok);
            }
        }
    }
    None
}

#[async_trait]
impl<'r> FromRequest<'r> for A<Session> {
    type Error = MyError;
    async fn from_request<'life0>(
        request: &'r Request<'life0>,
    ) -> request::Outcome<Self, Self::Error> {
        match session_from_request(request).await {
            Ok(x) => Outcome::Success(A(x)),
            Err(e) => {
                warn!("authentificated route rejected: {e:?}");
                Outcome::Forward(Status::Unauthorized)
            }
        }
    }
}
