//! POSIX serial transport via `tokio-serial`.

use async_trait::async_trait;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_serial::SerialPortBuilderExt;

use shared::error::{AutopilotError, Result};

use super::Transport;

#[derive(Debug)]
pub struct SerialTransport {
    port: tokio_serial::SerialStream,
}

impl SerialTransport {
    pub fn open(path: &str, baud: u32) -> Result<Self> {
        let port = tokio_serial::new(path, baud)
            .timeout(std::time::Duration::from_millis(500))
            .data_bits(tokio_serial::DataBits::Eight)
            .parity(tokio_serial::Parity::None)
            .stop_bits(tokio_serial::StopBits::One)
            .flow_control(tokio_serial::FlowControl::None)
            .open_native_async()
            .map_err(|e| AutopilotError::Network(format!("serial open {path}: {e}")))?;
        Ok(Self { port })
    }
}

#[async_trait]
impl Transport for SerialTransport {
    async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.port
            .read(buf)
            .await
            .map_err(|e| AutopilotError::Network(format!("serial read: {e}")))
    }

    async fn write_all(&mut self, buf: &[u8]) -> Result<()> {
        self.port
            .write_all(buf)
            .await
            .map_err(|e| AutopilotError::Network(format!("serial write: {e}")))?;
        Ok(())
    }
}
