#![warn(unused_extern_crates)]
#![allow(clippy::style)]

use serde::{Deserialize, Serialize};
use std::path::PathBuf;

use warp::{Filter, filters::path::FullPath};
#[path = "lib/curl.rs"]
mod curl;
#[path = "lib/html.rs"]
mod html;
#[path = "lib/markdowner.rs"]
mod markdowner;
#[path = "lib/sidebar.rs"]
mod sidebar;
use crate::{
    curl::curl_response, html::html_response, markdowner::MarkdownModule, sidebar::sidebar_content,
};

#[derive(Serialize, Deserialize)]
struct WebQuery {
    width: Option<i32>,
}

fn router(request_path: PathBuf) -> PathBuf {
    std::env::current_dir()
        .expect("unable to determine current directory")
        .join("serve")
        .join(request_path)
}

fn renderer(path: FullPath, user_agent: String, query: WebQuery) -> Box<dyn warp::Reply> {
    println!("{:?} requested by {}", path, user_agent);
    let request_path: PathBuf = path.as_str().strip_prefix("/").unwrap_or_default().into();
    let target_path = router(request_path);
    if !target_path.exists() || target_path.is_file() {
        return Box::new(warp::redirect(
            warp::http::uri::Builder::new()
                .authority(".")
                .build()
                .unwrap(),
        ));
    }

    println!("serving path: {:?}", target_path);

    let page_contents = markdowner::get_markdown_modules(&target_path);
    let sidebar_dir = PathBuf::from("assets/sidebar/");

    let sidebar_contents = sidebar_content(&router(sidebar_dir));

    let response = if user_agent.starts_with("curl/") {
        curl_response(page_contents, sidebar_contents, query.width)
    } else {
        html_response(
            page_contents,
            sidebar_contents,
            target_path
                .file_stem()
                .unwrap_or_default()
                .to_str()
                .unwrap_or_default()
                .to_owned(),
        )
    };
    response
}

#[tokio::main]
async fn main() {
    println!("Hello, world!");
    let assets = warp::path("assets").and(warp::fs::dir("./serve/assets/"));
    let favicon = warp::path("favicon.ico").and(warp::fs::file("./serve/favicon.ico"));

    let markdowns = warp::any() //path::end()
        .and(warp::path::full())
        .and(warp::header("user-agent"))
        .and(warp::query::<WebQuery>())
        .map(|path: FullPath, agent: String, query: WebQuery| renderer(path, agent, query));

    let routes = favicon.or(assets).or(markdowns);

    warp::serve(routes).run(([0, 0, 0, 0], 3030)).await;
}
