use bytes::Bytes;
use criterion::{Criterion, criterion_group, criterion_main};
use std::net::SocketAddr;
use std::sync::Arc;

use falcorn_core::http::{HttpMethod, HttpRequest};
use falcorn_core::python::asgi::{AsgiEnvironBuilder, AsgiResponseAdapter, AsgiSendEvent};

fn bench_asgi_scope_build(c: &mut Criterion) {
    let request = HttpRequest {
        raw: Bytes::new(),
        method: HttpMethod::Get,
        path: Bytes::from_static(b"/bench"),
        query_string: Some(Bytes::from_static(b"a=1&b=2")),
        version: http::Version::HTTP_11,
        headers: vec![(
            Bytes::from_static(b"host"),
            Bytes::from_static(b"localhost:8000"),
        )],
        body: Some(Arc::new(Bytes::from_static(b"hello"))),
        peer_addr: "127.0.0.1:8000".parse::<SocketAddr>().unwrap(),
    };

    c.bench_function("asgi_scope_build", |b| {
        b.iter(|| {
            pyo3::Python::attach(|py| {
                let scope = AsgiEnvironBuilder::from_request(py, &request);
                assert!(scope.is_ok());
            });
        });
    });
}

fn bench_asgi_response_parse(c: &mut Criterion) {
    let rt = tokio::runtime::Runtime::new().expect("runtime");
    c.bench_function("asgi_response_parse", |b| {
        b.iter(|| {
            rt.block_on(async {
                let (tx, rx) = tokio::sync::mpsc::channel(8);
                let _ = tx
                    .send(AsgiSendEvent::HttpResponseStart {
                        status: 200,
                        headers: vec![
                            (b"content-type".to_vec(), b"text/plain".to_vec()),
                            (b"server".to_vec(), b"falcorn".to_vec()),
                        ],
                    })
                    .await;
                let _ = tx
                    .send(AsgiSendEvent::HttpResponseBody {
                        body: b"ok".to_vec(),
                        more_body: false,
                    })
                    .await;
                drop(tx);

                let response = AsgiResponseAdapter::from_asgi_events(rx).await;
                assert!(response.is_ok());
            });
        });
    });
}

criterion_group!(asgi_flow, bench_asgi_scope_build, bench_asgi_response_parse);
criterion_main!(asgi_flow);
