use super::*;
use crate::pool::SKFileWriter;
use obikseq::kmer::CanonicalKmer;
use std::io::Cursor;
use tempfile::NamedTempFile;


const TEST_K: usize = 4;

fn setup() {
    obikseq::params::set_k(TEST_K);
}

fn make_sk(ascii: &[u8]) -> SuperKmer {
    SuperKmer::from_ascii(ascii)
}

fn make_sks(n: usize) -> Vec<SuperKmer> {
    (0..n)
        .map(|i| {
            let bases: Vec<u8> = (0..8).map(|j| b"ACGT"[(i + j) % 4]).collect();
            SuperKmer::from_ascii(&bases)
        })
        .collect()
}

#[test]
fn iter_all() {
    setup();
    let tmp = NamedTempFile::new().unwrap();
    let sks = make_sks(50);

    {
        let mut w = SKFileWriter::create(tmp.path()).unwrap();
        w.write_batch(&sks).unwrap();
    }

    let mut r = SKFileReader::open(tmp.path()).unwrap();
    let got: Vec<_> = r.iter().collect();
    assert_eq!(got.len(), 50);
    for (a, b) in sks.iter().zip(got.iter()) {
        assert_eq!(a.to_ascii(), b.to_ascii());
    }
}

#[test]
fn iter_canonical_kmers_count() {
    setup();
    let tmp = NamedTempFile::new().unwrap();
    let sks = make_sks(10); // each superkmer: seql=8, k=4 → 5 kmers

    {
        let mut w = SKFileWriter::create(tmp.path()).unwrap();
        w.write_batch(&sks).unwrap();
    }

    use std::fs;
    eprintln!("DEBUG: about to open");
    let sz = fs::metadata(tmp.path()).unwrap().len();
    eprintln!("DEBUG file size: {sz} bytes");
    let mut r = SKFileReader::open(tmp.path()).unwrap();
    eprintln!("DEBUG: reader opened, starting count");
    let count = r.iter_canonical_kmers().count();
    eprintln!("DEBUG: count = {count}");
    assert_eq!(count, 10 * 5);
}

#[test]
fn iter_canonical_kmers_matches_per_sk() {
    setup();
    let tmp = NamedTempFile::new().unwrap();
    let sks = make_sks(4);

    {
        let mut w = SKFileWriter::create(tmp.path()).unwrap();
        w.write_batch(&sks).unwrap();
    }

    // Reference: collect kmers superkmer by superkmer
    let expected: Vec<CanonicalKmer> = sks.iter().flat_map(|sk| sk.iter_canonical_kmers()).collect();

    let mut r = SKFileReader::open(tmp.path()).unwrap();
    let got: Vec<CanonicalKmer> = r.iter_canonical_kmers().collect();

    assert_eq!(expected, got);
}

// ── serialisation round-trips (formerly codec.rs tests) ──────────────────────

#[test]
fn roundtrip_single() {
    setup();
    let sk = make_sk(b"ACGTACGT");
    let mut buf = Vec::new();
    sk.write_to_binary(&mut buf).unwrap();

    let mut cur = Cursor::new(&buf);
    let got = read_superkmer(&mut cur).unwrap().unwrap();
    assert_eq!(sk.to_ascii(), got.to_ascii());
    assert_eq!(sk.seql(), got.seql());
}

#[test]
fn roundtrip_all_lengths() {
    obikseq::params::set_k(11);
    let bases: Vec<u8> = (0..300).map(|i| b"ACGT"[i % 4]).collect();
    for len in (11..=19).chain([255, 256, 257]) {
        let sk = make_sk(&bases[..len]);
        let mut buf = Vec::new();
        sk.write_to_binary(&mut buf).unwrap();

        let mut cur = Cursor::new(&buf);
        let got = read_superkmer(&mut cur).unwrap().unwrap();
        assert_eq!(sk.to_ascii(), got.to_ascii(), "len={len}");
        assert_eq!(sk.seql(), got.seql(), "len={len}");
    }
}

#[test]
fn eof_returns_none() {
    setup();
    let buf: Vec<u8> = vec![];
    let mut cur = Cursor::new(&buf);
    assert!(read_superkmer(&mut cur).unwrap().is_none());
}

#[test]
fn multiple_records() {
    setup();
    let seqs: &[&[u8]] = &[b"AAAA", b"CCCC", b"GGGG", b"TTTT"];
    let mut buf = Vec::new();
    for s in seqs {
        make_sk(s).write_to_binary(&mut buf).unwrap();
    }

    let mut cur = Cursor::new(&buf);
    for s in seqs {
        let got = read_superkmer(&mut cur).unwrap().unwrap();
        let expected = make_sk(s);
        assert_eq!(expected.to_ascii(), got.to_ascii());
    }
    assert!(read_superkmer(&mut cur).unwrap().is_none());
}
