use anyhow::{bail, Context};
use subprocess::{Popen, PopenConfig, Redirection};

use crate::packet::RawPacket;

// TODO eventually rewrite Ssdv in Rust?
// Don't want to use FFI because then segfaults can hurt us
pub fn ssdv_encode(callsign: &str, img: &[u8], img_idx: u8) -> anyhow::Result<Vec<RawPacket>> {
    let mut p = Popen::create(
        &[
            "ssdv",
            "-e",
            "-c",
            callsign,
            "-n",
            "-q",
            "6",
            "-i",
            &format!("{}", img_idx),
        ],
        PopenConfig {
            stdin: Redirection::Pipe,
            stdout: Redirection::Pipe,
            stderr: Redirection::Pipe,
            ..Default::default()
        },
    )?;

    let (stdout, stderr) = p.communicate_bytes(Some(img))?;

    if let Some(stderr) = stderr {
        if !stderr.is_empty() {
            eprintln!("{}", String::from_utf8_lossy(&stderr));
        }
    }

    let stdout = stdout.context("ssdv no stdout")?;

    if stdout.len() % 256 != 0 {
        bail!("ssdv returned garbage");
    }

    let mut out = vec![];
    let mut cur = [0; 256];
    let mut i = 0;
    for c in stdout {
        cur[i] = c;
        i += 1;
        if i == 256 {
            out.push(RawPacket(cur));
            i = 0;
        }
    }

    Ok(out)
}