use crate::{app::AppDepot, templates, utils::render::RenderExt};
use anyhow::Result;
use salvo::{fs::NamedFile, prelude::*};

pub fn routes() -> Router {
    Router::new()
        .push(Router::with_path("/posts/{slug}").get(get_post))
        .push(Router::with_path("/posts/{slug}/{attachment}").get(get_attachment))
}

#[handler]
async fn get_post(req: &mut Request, res: &mut Response, depot: &mut Depot) -> Result<()> {
    let slug: &str = req.param("slug").unwrap_or_default();
    let normalized_slug = slug.to_lowercase();
    if slug != normalized_slug {
        res.render(Redirect::permanent(format!("/posts/{}/", normalized_slug)));
        return Ok(());
    }

    let state = depot.app_state();

    if let Some(post) = state.blog_service.get_post(&normalized_slug) {
        res.render_html(|o| templates::posts::post_html(o, &state.app_config, post))?;
    } else {
        res.status_code(StatusCode::NOT_FOUND);
    }

    Ok(())
}

#[handler]
pub async fn get_attachment(
    req: &mut Request,
    depot: &mut Depot,
    res: &mut Response,
) -> Result<()> {
    let slug: &str = req.param("slug").unwrap_or_default();
    let attachment_name: &str = req.param("attachment").unwrap_or_default();
    let normalized_slug = slug.to_lowercase();
    if slug != normalized_slug {
        res.render(Redirect::other(format!(
            "/posts/{}/{}",
            normalized_slug, attachment_name
        )));
        return Ok(());
    }

    let state = depot.app_state();

    if let Some(post) = state.blog_service.get_post(slug) {
        if let Some(attachment) = post.attachments.get(attachment_name) {
            let file = NamedFile::open(&attachment.path).await?;
            file.send(req.headers(), res).await;
            return Ok(());
        }
    }

    res.status_code(StatusCode::NOT_FOUND);

    Ok(())
}
