use axum::body::Body;
use axum::extract::{Path as UrlPath, Request, State};
use axum::http::Uri;
use axum::response::{IntoResponse, Redirect, Response};
use tower::ServiceExt;
use crate::drive::api_types::Refusal;
use crate::drive::server_mode::published::{Mount, Published};
pub async fn to_folder(UrlPath(id): UrlPath<String>) -> Response {
Redirect::permanent(&format!("{}/", Mount::Latest.path(&id))).into_response()
}
pub async fn latest_root(
State(published): State<Published>,
UrlPath(id): UrlPath<String>,
request: Request,
) -> Result<Response, Refusal> {
serve(&published, &id, Mount::Latest, "/", request).await
}
pub async fn in_document(
State(published): State<Published>,
UrlPath((id, rest)): UrlPath<(String, String)>,
request: Request,
) -> Result<Response, Refusal> {
let (mount, path) = match pinned(&rest) {
Some((n, path)) => (Mount::Pinned(n), path),
None => (Mount::Latest, format!("/{rest}")),
};
match (mount, path.as_str()) {
(Mount::Pinned(n), "/download") => super::pages::download(&published, &id, n).await,
(_, "/__devpage/versions") => super::pages::versions(&published, &id, mount),
_ => serve(&published, &id, mount, &path, request).await,
}
}
fn pinned(rest: &str) -> Option<(u64, String)> {
let after = rest.strip_prefix("v/")?;
let (n, path) = after.split_once('/').unwrap_or((after, ""));
Some((n.parse().ok()?, format!("/{path}")))
}
async fn serve(
published: &Published,
id: &str,
mount: Mount,
path: &str,
request: Request,
) -> Result<Response, Refusal> {
let version = published.version(id, mount).await?;
let (mut parts, body) = request.into_parts();
let query = parts
.uri
.query()
.map(|q| format!("?{q}"))
.unwrap_or_default();
parts.uri = format!("{path}{query}")
.parse::<Uri>()
.unwrap_or_else(|_| Uri::from_static("/"));
parts.extensions = Default::default();
Ok(version
.router()
.oneshot(Request::from_parts(parts, Body::new(body)))
.await
.into_response())
}