use serde::Serialize;

#[derive(Clone, Serialize, Debug)]
pub struct FrameTiming {
    pub pts_ms: Option<u64>,
    pub dts_ms: u64,
}

#[derive(Clone, Serialize, Debug)]
pub struct RecordedFrame<F> {
    pub timing: FrameTiming,
    pub frame: F,
}

#[derive(Clone, Default)]
pub struct Recording<F> {
    pub frames: Vec<RecordedFrame<F>>,
    pub count: usize,
    pub except_count: Option<usize>,
}

impl<F> Recording<F> {
    pub fn new() -> Recording<F> {
        Self {
            frames: Vec::new(),
            count: 0,
            except_count: None,
        }
    }
    pub fn with_except_count(except_count: usize) -> Recording<F> {
        Self {
            frames: Vec::new(),
            count: 0,
            except_count: Some(except_count),
        }
    }
    pub fn push(&mut self, ite: RecordedFrame<F>) {
        self.frames.push(ite);
    }
    pub fn check_frame_need_record(ite: RecordedFrame<F>) {}
}

pub trait CsvExporter<F> {
    type Error: std::error::Error + Send + Sync + 'static;
    fn csv_header(&self, recording: &Recording<F>) -> Vec<String>;
    fn csv_row(&self, item: &RecordedFrame<F>) -> anyhow::Result<Option<Vec<String>>>;
}

// TODO: CsvImporter
pub trait CsvImporter<P> {
    fn load<R: std::io::Read>(&mut self, reader: R) -> anyhow::Result<Vec<P>>;
}

pub fn write_csv<F, E, W>(recording: &Recording<F>, exporter: &E, writer: W) -> anyhow::Result<()>
where
    E: CsvExporter<F>,
    W: std::io::Write,
{
    let header = exporter.csv_header(&recording);
    let mut wrt = csv::Writer::from_writer(writer);
    wrt.write_record(header)?;
    for f in &recording.frames {
        if let Some(row) = exporter.csv_row(f)? {
            wrt.write_record(&row)?;
        }
    }

    wrt.flush()?;

    Ok(())
}
