Documentation
use poem::{
    listener::TcpListener, Endpoint, IntoResponse, Request, Response, Result, Route, Server,
};

#[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("*", Hello(Some("world".to_string())));
        dbg!(self.url());
        Ok(Server::new(TcpListener::bind(self.addr()))
            .name("Hello")
            .run(app)
            .await?)
    }
}

#[derive(Clone)]
pub struct Hello(Option<String>);

impl IntoResponse for Hello {
    fn into_response(self) -> Response {
        let msg = match self.0 {
            Some(name) => format!("hello {}", name),
            None => format!("hello"),
        };
        msg.into_response()
    }
}

impl Endpoint for Hello {
    type Output = Self;
    async fn call(&self, req: Request) -> Result<Self::Output> {
        let path = req.uri().path();
        let res = match path {
            "/" => self.clone(),
            _ => Hello(Some(path[1..].to_string())),
        };
        Ok(res)
    }
}