use aex::connection::context::TypeMapExt;
use aex::exe;
use aex::http::meta::HttpMetadata;
use aex::http::protocol::header::HeaderKey;
use aex::http::router::{NodeType, Router as HttpRouter};
use aex::http::types::Executor;
use aex::server::HTTPServer;
use aex::tcp::types::{Command, RawCodec};
use std::net::SocketAddr;
use std::sync::Arc;

fn auth_middleware() -> Arc<Executor> {
    exe!(|ctx| {
        let meta = ctx.local.get_value::<HttpMetadata>().unwrap();
        let auth_header = meta.headers.get(&HeaderKey::Authorization);

        if auth_header.is_none() {
            ctx.send("Unauthorized: Missing Authorization header", None);
            return false;
        }

        let token = auth_header.unwrap();
        if !token.starts_with("Bearer ") {
            ctx.send("Unauthorized: Invalid token format", None);
            return false;
        }

        ctx.local.set_value::<String>("user_123".to_string());
        true
    })
}

fn logging_middleware() -> Arc<Executor> {
    exe!(|ctx| {
        let meta = ctx.local.get_value::<HttpMetadata>().unwrap();
        println!("[{:?}] {} {}", meta.method, meta.path, ctx.addr);
        true
    })
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let addr: SocketAddr = "0.0.0.0:8080".parse()?;
    let mut router = HttpRouter::new(NodeType::Static("root".into()));

    let auth = auth_middleware();
    let logger = logging_middleware();

    router
        .get(
            "/api/users",
            exe!(|ctx| {
                ctx.send(r#"["user1", "user2", "user3"]"#, None);
                true
            }),
        )
        .middleware(logger.clone())
        .register();

    router
        .get(
            "/api/users/:id",
            exe!(|ctx| {
                let meta = ctx.local.get_value::<HttpMetadata>().unwrap();
                let id = meta
                    .params
                    .as_ref()
                    .and_then(|p| p.data.as_ref())
                    .and_then(|d| d.get("id"))
                    .map(|v| v.as_str())
                    .unwrap_or("unknown");
                ctx.send(format!(r#"{{"id":"{}","name":"User {}"}}"#, id, id), None);
                true
            }),
        )
        .middleware(auth.clone())
        .middleware(logger.clone())
        .register();

    router
        .post(
            "/api/users",
            exe!(|ctx| {
                let meta = ctx.local.get_value::<HttpMetadata>().unwrap();
                let body = String::from_utf8_lossy(&meta.body);
                println!("Create user: {}", body);
                ctx.send(format!(r#"{{"status":"created","data":{}}}"#, body), None);
                true
            }),
        )
        .middleware(auth.clone())
        .middleware(logger.clone())
        .register();

    router
        .get(
            "/public/*",
            exe!(|ctx| {
                let meta = ctx.local.get_value::<HttpMetadata>().unwrap();
                ctx.send(format!(r#"{{"path":"{}"}}"#, meta.path), None);
                true
            }),
        )
        .register();

    println!("Server running at http://{}", addr);
    println!("Try:");
    println!("  curl http://{}/public/info", addr);
    println!("  curl http://{}/api/users", addr);
    println!(
        "  curl -H 'Authorization: Bearer token' http://{}/api/users/123",
        addr
    );

    HTTPServer::new(addr, None).http(router).start().await?;
    Ok(())
}
