use std::collections::HashMap;
use std::io::Cursor;

use mig_bo4e::{DataBundle, VariantCache};

fn empty_variant_cache() -> VariantCache {
    VariantCache {
        message_defs: vec![],
        transaction_defs: HashMap::new(),
        combined_defs: HashMap::new(),
        code_lookups: HashMap::new(),
        mig_schema: None,
        segment_structure: None,
        pid_segment_numbers: HashMap::new(),
        pid_requirements: HashMap::new(),
        tx_groups: HashMap::new(),
    }
}

#[test]
fn test_data_bundle_roundtrip_bincode() {
    let mut variants = HashMap::new();
    variants.insert("UTILMD_Strom".to_string(), empty_variant_cache());

    let bundle = DataBundle {
        format_version: "FV2504".to_string(),
        bundle_version: DataBundle::CURRENT_VERSION,
        variants,
    };

    let mut buf = Vec::new();
    bundle.write_to(&mut buf).expect("write_to should succeed");
    assert!(!buf.is_empty(), "serialized bundle should not be empty");

    let mut cursor = Cursor::new(&buf);
    let loaded = DataBundle::read_from(&mut cursor).expect("read_from should succeed");

    assert_eq!(loaded.format_version, "FV2504");
    assert_eq!(loaded.bundle_version, DataBundle::CURRENT_VERSION);
    assert!(loaded.variants.contains_key("UTILMD_Strom"));
    assert_eq!(loaded.variants.len(), 1);
}

#[test]
fn test_data_bundle_rejects_incompatible_version() {
    let bundle = DataBundle {
        format_version: "FV9999".to_string(),
        bundle_version: 9999,
        variants: HashMap::new(),
    };

    let mut buf = Vec::new();
    bundle.write_to(&mut buf).expect("write_to should succeed");

    let mut cursor = Cursor::new(&buf);
    let result = DataBundle::read_from_checked(&mut cursor);

    assert!(result.is_err(), "should reject incompatible version");
    let err_msg = result.err().unwrap().to_string();
    assert!(
        err_msg.contains("version"),
        "error should mention version, got: {err_msg}"
    );
}

#[test]
fn test_data_bundle_variant_lookup() {
    let mut variants = HashMap::new();
    variants.insert("MSCONS".to_string(), empty_variant_cache());

    let bundle = DataBundle {
        format_version: "FV2504".to_string(),
        bundle_version: DataBundle::CURRENT_VERSION,
        variants,
    };

    assert!(
        bundle.variant("MSCONS").is_some(),
        "should find MSCONS variant"
    );
    assert!(
        bundle.variant("NONEXISTENT").is_none(),
        "should not find nonexistent variant"
    );
}
