use std::fs::File;
use std::path::Path;
use rand::Rng;
use crate::cli::cli::OutputFormat;
use crate::system::model::DLASystem;
use crate::system::{Position, Storage};
use crate::system::spawner::Spawner;
use crate::system::sticker::Sticker;
use crate::system::walker::Walker;

pub fn write<R: Rng, P: Position, S: Storage<P>, W: Walker<P>, Sp: Spawner<P>, St: Sticker<P, S>>(
    sys: &DLASystem<R, P, S, W, Sp, St>,
    format: OutputFormat,
    output: &Path,
) {
    match format {
        OutputFormat::FullDataJson => write_json_full_data(sys, output),
        OutputFormat::Positions => write_csv_positions(sys, output),
    }
}

fn write_csv_positions<R: Rng, P: Position, S: Storage<P>, W: Walker<P>, Sp: Spawner<P>, St: Sticker<P, S>>(sys: &DLASystem<R, P, S, W, Sp, St>, csv_path: &Path) {
    let mut wtr = csv::Writer::from_path(csv_path)
        .expect("Failed to open file");

    // CSVs can only store the raw positions
    let positions: Vec<&P> = sys.history
        .iter()
        .map(|line| &line.position)
        .collect();

    wtr.serialize(positions)
        .unwrap();

    wtr.flush()
        .unwrap();
}

fn write_json_full_data<R: Rng, P: Position, S: Storage<P>, W: Walker<P>, Sp: Spawner<P>, St: Sticker<P, S>>(sys: &DLASystem<R, P, S, W, Sp, St>, output_path: &Path) {
    let file = File::create(output_path).expect("Failed to open file");

    serde_json::to_writer_pretty(file, &sys.history)
        .expect("Failed to write json");
}
