Documentation
use gdbg::dbg;
use poem::{handler, listener::TcpListener, web::Json, Request, Route, Server};
use querystring::querify;
use serde::Serialize;
use std::collections::BTreeMap;

#[derive(clap::Parser)]
pub struct Options {
    #[clap(long, env = "HOST", default_value = "127.0.0.1")]
    /// Set host
    host: String,
    #[clap(short = 'p', long, env = "PORT", default_value = "8080")]
    /// Set listening port
    port: String,
}

impl Options {
    fn host(&self) -> String {
        self.host.clone()
    }
    fn port(&self) -> String {
        self.port.clone()
    }
    fn hostport(&self) -> String {
        format!("{}:{}", self.host(), self.port())
    }
    fn url(&self) -> String {
        format!("http://{}", self.hostport())
    }
    fn addr(&self) -> std::net::SocketAddr {
        self.hostport().parse().unwrap()
    }
    pub async fn run(&mut self) -> Result<(), anyhow::Error> {
        let app = Route::new().at("*", echo);
        dbg!(self.url());
        Ok(Server::new(TcpListener::bind(self.addr()))
            .name("hello")
            .run(app)
            .await?)
    }
}

#[derive(Debug, Serialize)]
pub struct Response {
    method: String,
    path: String,
    query: String,
    headers: BTreeMap<String, Vec<String>>,
    values: BTreeMap<String, Vec<String>>,
}

pub fn echo_impl(req: &Request) -> Response {
    let method = req.method().to_string();
    let path = req.uri().path().to_string();
    let query = req.uri().query().unwrap_or("").to_string();

    let headers = req
        .headers()
        .iter()
        .map(|(name, value)| {
            (
                name.as_str().to_string(),
                value.to_str().unwrap().to_string(),
            )
        })
        .fold(
            BTreeMap::<String, Vec<String>>::new(),
            |mut acc: BTreeMap<_, _>, (left, right)| {
                acc.entry(left)
                    .and_modify(|values| values.push(right.clone()))
                    .or_insert(vec![right]);
                acc
            },
        );

    dbg!(querify(&query));
    let values = querify(&query)
        .iter()
        .map(|(name, value)| (name.to_string(), value.to_string()))
        .fold(
            BTreeMap::<String, Vec<String>>::new(),
            |mut acc: BTreeMap<_, _>, (left, right)| {
                dbg!((&left, &right));
                acc.entry(left)
                    .and_modify(|values| values.push(right.clone()))
                    .or_insert(vec![right]);
                acc
            },
        );

    Response {
        method,
        path,
        query,
        headers,
        values,
    }
}

#[handler]
pub fn echo(req: &Request) -> Json<Response> {
    Json(echo_impl(req))
}