use std::sync::Arc;
use tonic::{Request, Response, Status};
use roto_runtime::RotoOwned;
use roto_tonic::{BufferPool, generated::helloworld::{Greeter, GreeterServer, OwnedHelloRequest, OwnedHelloReply, HelloReplyBuilder, HelloBuilder}};
use std::net::SocketAddr;
use tokio::net::TcpListener;

struct MyGreeter;

#[tonic::async_trait]
impl Greeter for MyGreeter {
    async fn say_hello(&self, request: Request<OwnedHelloRequest>) -> std::result::Result<Response<OwnedHelloReply>, Status> {
        let req = request.into_inner();
        let hello_req = req.reader();

        // Extract name from the nested Hello message in HelloRequest
        let name = match hello_req.request() {
            Ok(req_bytes) => {
                let hello = roto_tonic::generated::helloworld::Hello::new(req_bytes).unwrap();
                hello.name_or_default().unwrap().to_string()
            },
            Err(_) => "Unknown".to_string(),
        };

        // Build the Hello response message
        let mut hello_buf = [0u8; 1024];
        let mut hello_builder = HelloBuilder::builder(&mut hello_buf);
        hello_builder = hello_builder.name(&format!("Hello, {}!", name))
            .map_err(|e| Status::internal(format!("Build error: {:?}", e)))?;

        let hello_bytes = hello_builder.finish()
            .map_err(|e| Status::internal(format!("Finish error: {:?}", e)))?;

        // Build the HelloReply message containing the Hello bytes
        let mut reply_buf = [0u8; 1024];
        let mut reply_builder = HelloReplyBuilder::builder(&mut reply_buf);
        reply_builder = reply_builder.response(hello_bytes)
            .map_err(|e| Status::internal(format!("Build error: {:?}", e)))?;

        let reply_bytes = reply_builder.finish()
            .map_err(|e| Status::internal(format!("Finish error: {:?}", e)))?;

        Ok(Response::new(OwnedHelloReply {
            data: reply_bytes.to_vec().into(),
        }))
    }
}

#[tokio::test]
async fn test_say_hello_handler() {
    let greeter = MyGreeter;

    // Manually construct a valid proto buffer for HelloRequest
    // HelloRequest { request: Hello { name: "World" } }
    let mut hello_buf = [0u8; 1024];
    let mut hb = HelloBuilder::builder(&mut hello_buf);
    hb = hb.name("World").unwrap();
    let hello_bytes = hb.finish().unwrap();

    let mut req_buf = [0u8; 1024];
    let mut rb = roto_tonic::generated::helloworld::HelloRequestBuilder::builder(&mut req_buf);
    rb = rb.request(hello_bytes).unwrap();
    let req_bytes = rb.finish().unwrap();

    let request = Request::new(OwnedHelloRequest {
        data: req_bytes.to_vec().into(),
    });

    let response = greeter.say_hello(request).await.unwrap();
    let reply = response.into_inner();
    let reply_reader = reply.reader();

    let response_msg_bytes = reply_reader.response().expect("Response field missing");
    let response_msg = roto_tonic::generated::helloworld::Hello::new(response_msg_bytes).expect("Invalid Hello message");

    assert_eq!(response_msg.name_or_default().unwrap(), "Hello, World!");
}

#[tokio::test]
async fn test_server_start() {
    let pool = Arc::new(BufferPool::new(1024));
    let greeter = Arc::new(MyGreeter);
    let server = GreeterServer::new(greeter, pool);

    let addr = SocketAddr::from(([127, 0, 0, 1], 0));
    let listener = TcpListener::bind(addr).await.unwrap();
    let _local_addr = listener.local_addr().unwrap();

    let server_handle = tokio::spawn(async move {
        tonic::transport::Server::builder()
            .add_service(server)
            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
            .await
            .unwrap();
    });

    // Just verify it can start without crashing
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    server_handle.abort();
}
