use assert_cmd::cargo::cargo_bin_cmd;
use bstr::ByteSlice;

use crate::common::twitcher_with_ref;

mod common;

fn test_has_ts(file: &str, padding: u32) {
    let cmd = twitcher_with_ref(&format!(
        "tests/data/{file} --padding {padding} --cluster-min-records 1 -vv"
    ));
    assert!(cmd.status.success());
    let stdout_str = cmd.stdout.as_bstr();
    let stderr_str = cmd.stderr.as_bstr();
    eprintln!("{stderr_str}");
    let records: Vec<_> = stdout_str
        .lines()
        .filter(|l| !l.starts_with(b"#"))
        .collect();
    for r in &records {
        println!("{}", r.as_bstr());
    }
    let has_ts = records.iter().any(|r| r.contains_str(b"CIGARETS"));
    assert!(has_ts);
}

#[test]
fn test_single_mnv() {
    test_has_ts("single_mnv.vcf", 10);
}

#[test]
fn test_single_insertion() {
    test_has_ts("single_insertion.vcf", 20);
}

#[test]
fn test_output_sorted() {
    let cmd = twitcher_with_ref("tests/data/sorted_output.vcf.gz --padding 20");
    assert!(cmd.status.success());
    let mut last_chr = None;
    let mut last_pos = 0;
    for record in cmd
        .stdout
        .as_bstr()
        .lines()
        .filter(|l| !l.starts_with(b"#"))
    {
        let mut tokens = record.as_bstr().split_str(b"\t");
        let chr = tokens.next().unwrap();
        assert!(
            last_chr.is_none_or(|last| last == chr),
            "the chr is changing for an example where it shouldn't",
        );
        last_chr = Some(chr);
        let pos = tokens.next().unwrap().to_str().unwrap().parse().unwrap();
        assert!(pos >= last_pos, "The output is not sorted");
        last_pos = pos;
    }
}

fn test_region_output(filename: &str, expected: &str) {
    let dir = tempfile::tempdir().unwrap();
    let regions = format!("{}/{filename}", dir.path().to_str().unwrap());
    let mut cmd = cargo_bin_cmd!("twitcher");
    cmd.args([
        "vcf",
        "./test_files/test.vcf",
        "--reference",
        "./test_files/test.fa",
        "--output-regions",
        &regions,
        "--cluster-min-records",
        "1",
    ]);
    let res = cmd.unwrap();
    assert!(res.status.success());
    let output = std::fs::read_to_string(regions).unwrap();
    assert_eq!(output, expected);
}

#[test]
fn test_region_output_tab() {
    test_region_output("regions.some.ext", "chrZ\t101\t108\nchrZ\t201\t207\n");
}

#[test]
fn test_region_output_bed() {
    test_region_output("regions.bed", "chrZ\t100\t108\nchrZ\t200\t207\n");
}
