use std::sync::Arc;

use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};

use crate::error::Result;
use crate::handlers::RequestHandler;
use crate::protocol::JsonRpcRequest;

pub struct StdioTransport {
    request_handler: Arc<RequestHandler>,
}

impl StdioTransport {
    pub fn new(request_handler: Arc<RequestHandler>) -> Self {
        Self { request_handler }
    }

    pub async fn start(&self) -> Result<()> {
        let stdin = tokio::io::stdin();
        let stdout = tokio::io::stdout();
        let mut reader = BufReader::new(stdin);
        let mut writer = stdout;

        let mut line = String::new();
        loop {
            line.clear();
            let n = reader.read_line(&mut line).await?;

            if n == 0 {
                tracing::info!("Stdio transport: EOF received, shutting down");
                break;
            }

            let request: JsonRpcRequest = match serde_json::from_str(&line) {
                Ok(r) => r,
                Err(e) => {
                    let error_response = serde_json::json!({
                        "jsonrpc": "2.0",
                        "id": serde_json::json!(null),
                        "error": {
                            "code": -32700,
                            "message": "Parse error",
                            "data": { "details": e.to_string() }
                        }
                    });
                    writer
                        .write_all(
                            format!("{}\n", serde_json::to_string(&error_response)?).as_bytes(),
                        )
                        .await?;
                    writer.flush().await?;
                    continue;
                }
            };

            let response = self.request_handler.handle(&request).await;

            writer
                .write_all(format!("{}\n", serde_json::to_string(&response)?).as_bytes())
                .await?;
            writer.flush().await?;
        }

        Ok(())
    }
}
