/*
SPDX-License-Identifier: GPL-3.0-or-later
Copyright © 2024 Mike Robeson [dijksterhuis]
*/

mod helpers;

use helpers::*;
use ot_tools_io::{
    ArrangementFile, BankFile, MarkersFile, OctatrackFileIO, ProjectFile, SampleSettingsFile,
};
use std::path::Path;

const BASE_TEST_CATEGORY: &str = "yaml_file_to_bin_file";

mod arrangement {
    use super::*;

    #[test]
    fn blank() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "blank.work",
            &get_arrange_dirpath().join("blank.yaml"),
            &get_arrange_dirpath().join("blank.work"),
        )
    }

    #[test]
    fn full_options() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "full-options.work",
            &get_arrange_dirpath().join("full-options.yaml"),
            &get_arrange_dirpath().join("full-options.work"),
        )
    }

    #[test]
    fn full_options_no_rems() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "full-options-no-rems.work",
            &get_arrange_dirpath().join("full-options-no-rems.yaml"),
            &get_arrange_dirpath().join("full-options-no-rems.work"),
        )
    }

    #[test]
    fn no_saved_flag() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "no-saved-flag.work",
            &get_arrange_dirpath().join("no-saved-flag.yaml"),
            &get_arrange_dirpath().join("no-saved-flag.work"),
        )
    }

    #[test]
    fn with_saved_flag() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "with-saved-flag.work",
            &get_arrange_dirpath().join("with-saved-flag.yaml"),
            &get_arrange_dirpath().join("with-saved-flag.work"),
        )
    }

    #[test]
    fn blank_diffname_1() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "bank-diffname1.work",
            &get_arrange_dirpath().join("blank-diffname1.yaml"),
            &get_arrange_dirpath().join("blank-diffname1.work"),
        )
    }

    #[test]
    fn blank_diffname_2() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "blank-diffname2.work",
            &get_arrange_dirpath().join("blank-diffname2.yaml"),
            &get_arrange_dirpath().join("blank-diffname2.work"),
        )
    }

    #[test]
    fn four_patterns() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "4-patterns.work",
            &get_arrange_dirpath().join("4-patterns.yaml"),
            &get_arrange_dirpath().join("4-patterns.work"),
        )
    }

    #[test]
    fn one_pattern() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-pattern.work",
            &get_arrange_dirpath().join("1-pattern.yaml"),
            &get_arrange_dirpath().join("1-pattern.work"),
        )
    }

    #[test]
    fn one_halt() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-halt.work",
            &get_arrange_dirpath().join("1-halt.yaml"),
            &get_arrange_dirpath().join("1-halt.work"),
        )
    }

    #[test]
    fn one_pattern_1_loop() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-patt-1-loop.work",
            &get_arrange_dirpath().join("1-patt-1-loop.yaml"),
            &get_arrange_dirpath().join("1-patt-1-loop.work"),
        )
    }

    #[test]
    fn one_pattern_1_loop_1_jump() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-patt-1-jump-1-loop.work",
            &get_arrange_dirpath().join("1-patt-1-jump-1-loop.yaml"),
            &get_arrange_dirpath().join("1-patt-1-jump-1-loop.work"),
        )
    }

    #[test]
    fn one_pattern_1_loop_1_jump_1_halt() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-patt-1-jump-1-loop-1-halt.work",
            &get_arrange_dirpath().join("1-patt-1-jump-1-loop-1-halt.yaml"),
            &get_arrange_dirpath().join("1-patt-1-jump-1-loop-1-halt.work"),
        )
    }

    #[test]
    fn one_rems_no_txt() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-rem-bank-txt.work",
            &get_arrange_dirpath().join("1-rem-blank-txt.yaml"),
            &get_arrange_dirpath().join("1-rem-blank-txt.work"),
        )
    }

    #[test]
    fn one_rems_chain_txt() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "1-rem-CHAIN-txt.work",
            &get_arrange_dirpath().join("1-rem-CHAIN-txt.yaml"),
            &get_arrange_dirpath().join("1-rem-CHAIN-txt.work"),
        )
    }

    #[test]
    fn two_rems_chain_txt() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "2-rem-CHAIN-txt.work",
            &get_arrange_dirpath().join("2-rem-CHAIN-txt.yaml"),
            &get_arrange_dirpath().join("2-rem-CHAIN-txt.work"),
        )
    }

    #[test]
    fn blank_same_name_saved() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "blank-samename-saved-chktest.work",
            &get_arrange_dirpath().join("blank-samename-saved-chktest.yaml"),
            &get_arrange_dirpath().join("blank-samename-saved-chktest.work"),
        )
    }

    #[test]
    fn blank_same_name_unsaved() -> RBoxErr<()> {
        helper_runner::<ArrangementFile>(
            "arrangement",
            "blank-samename-unsaved-chktest.work",
            &get_arrange_dirpath().join("blank-samename-unsaved-chktest.yaml"),
            &get_arrange_dirpath().join("blank-samename-unsaved-chktest.work"),
        )
    }
}

fn helper_runner<T>(
    test_name: &str,
    out_bin_fname: &str,
    src_yaml_path: &Path,
    valid_bin_path: &Path,
) -> RBoxErr<()>
where
    T: OctatrackFileIO,
    T: std::fmt::Debug,
    T: PartialEq,
{
    let outdir = get_temp_dirpath(BASE_TEST_CATEGORY).join(test_name);
    println!("outdir: {}", outdir.display());
    maybe_create_dir_all(&outdir)?;
    println!("outdir created: {}", outdir.display());

    let outfile = outdir.join(out_bin_fname);
    println!("creating bin data file: {}", outfile.display());
    let r = T::from_yaml_file(src_yaml_path)?.to_data_file(&outfile);
    print_and_assert_ok_result(r);

    println!("reading written: {}", outfile.display());
    let written = T::from_data_file(&outfile)?;
    println!("reading valid: {}", valid_bin_path.display());
    let valid = T::from_data_file(valid_bin_path)?;
    // let _ = std::fs::remove_file(&outfile);
    assert_eq!(written, valid);

    Ok(())
}

#[test]
fn project() -> RBoxErr<()> {
    helper_runner::<ProjectFile>(
        "project",
        "project-default.work",
        &get_project_dirpath().join("default.yaml"),
        &get_project_dirpath().join("default.work"),
    )
}

#[test]
fn bank() -> RBoxErr<()> {
    helper_runner::<BankFile>(
        "bank",
        "bank-default.work",
        &get_bank_dirpath().join("default.yaml"),
        &get_bank_dirpath().join("default.work"),
    )
}

// stack overflowing for some reason when calling `ot_tools_io::deserialize_yaml_to_type` :(
#[test]
#[ignore]
fn markers() -> RBoxErr<()> {
    println!("hello");
    helper_runner::<MarkersFile>(
        "markers",
        "markers-default.work",
        &get_markers_dirpath().join("default.yaml"),
        &get_markers_dirpath().join("default.work"),
    )
}

#[test]
fn sample() -> RBoxErr<()> {
    helper_runner::<SampleSettingsFile>(
        "sample",
        "samples-base.ot",
        &get_samples_dirpath().join("sample.yaml"),
        &get_samples_dirpath().join("sample.ot"),
    )
}
