use std::str::FromStr;

use axum::{
    extract::{FromRequestParts, OriginalUri},
    http::{Uri, request::Parts},
};
use axum_extra::extract::Host;

/// Extractor for the remote URL
pub(crate) struct RemoteUrl(pub Uri);

impl<S> FromRequestParts<S> for RemoteUrl
where
    S: Send + Sync,
{
    type Rejection = &'static str;

    async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
        let uri = OriginalUri::from_request_parts(parts, state).await.unwrap();

        let url = if uri.0.scheme().is_some() {
            uri.0
        } else {
            let host = Host::from_request_parts(parts, state)
                .await
                .map_err(|_| "Unable to extract host")?;

            let proto = parts
                .headers
                .get("X-Forwarded-Proto")
                .and_then(|f| f.to_str().ok())
                .unwrap_or("http");

            let url = format!("{}://{}{}", proto, host.0, uri.0);
            Uri::from_str(&url).unwrap()
        };

        Ok(RemoteUrl(url))
    }
}
