use std::{collections::HashMap, path::PathBuf};

use http::handling::{
    file_handlers::NamedFile,
    methods::Method,
    request::Request,
    response::{Outcome, Response, ResponseBody, Status},
    routes::{Data, Route},
};

fn hashmap_to_string(map: &HashMap<&str, &str>) -> String {
    let mut result = String::new();
    for (key, value) in map {
        result.push_str(key);
        result.push('=');
        result.push_str(value);
        result.push(';');
    }
    result.pop(); // Remove the trailing semicolon if desired
    result
}

fn handle_static_hi(request: Request<'_>, data: Data) -> Outcome<Response, Status, Data> {
    let keys = if let Ok(keys) = request.get_get_form_keys(vec!["asdf", "jkl"]) {
        keys
    } else {
        return Outcome::Forward(data);
    };
    let response = hashmap_to_string(&keys);
    Outcome::Success(Response {
        headers: vec![
            format!("Content-Length: {}", response.len()),
            format!("Content-Type: text/plain"),
        ],
        status: Some(Status::Ok),
        body: Box::new(response),
    })
    // Outcome::Forward(data)
}

fn handler(request: Request<'_>, _data: Data) -> Outcome<Response, Status, Data> {
    let response = fileserver(request.uri.strip_prefix("static/").unwrap());
    let response = match response {
        Ok(dat) => Response {
            headers: vec![
                format!("Content-Length: {}", dat.get_len()),
                format!("Content-Type: {}", dat.get_mime()),
            ],
            status: Some(Status::Ok),
            body: Box::new(dat),
        },
        Err(_) => return Outcome::Failure(Status::NotFound),
    };
    Outcome::Success(response)
}

fn fileserver(path: &str) -> Result<NamedFile, Status> {
    NamedFile::open(PathBuf::from("static/".to_string() + path))
}

fn post_hi_handler(_request: Request, data: Data) -> Outcome<Response, Status, Data> {
    if data.is_empty() {
        return Outcome::Forward(data);
    }
    let data = if let Ok(str) = String::from_utf8(data.buffer) {
        str
    } else {
        return Outcome::Failure(Status::BadRequest);
    };
    let dat = post_hi(data);
    Outcome::Success(Response {
        headers: vec![
            format!("Content-Length: {}", dat.len()),
            format!("Content-Type: text/plain"),
        ],
        status: Some(Status::Ok),
        body: Box::new(dat),
    })
}

fn post_hi(msg: String) -> String {
    msg
}

#[tokio::main]
async fn main() {
    let fileserver = Route {
        format: None,
        handler,
        name: Some("file_server"),
        uri: "static/<path..>",
        method: Method::Get,
        rank: 1,
    };

    let post_test = Route {
        format: None,
        handler: post_hi_handler,
        name: Some("post_test"),
        uri: "post",
        method: Method::Post,
        rank: 0,
    };

    let static_hi = Route {
        format: None,
        handler: handle_static_hi,
        name: Some("Handle_Static_hi"),
        uri: "static/hi",
        method: Method::Get,
        rank: 0,
    };

    http::build("192.168.178.32:8000")
        .await
        .mount("/", vec![fileserver, post_test, static_hi])
        .mount("/post/", vec![post_test])
        .launch()
        .await;
}