use std::fs;
use std::path::PathBuf;

use tempfile::tempdir;
use rpki::source::ccr::{
    ParsedAspa, ParsedCcrSnapshot, ParsedVrp, find_latest_ccr_file, load_ccr_snapshot_from_file,
    snapshot_to_payloads_with_options,
};

fn fixture_path(name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("data").join(name)
}

#[test]
#[ignore = "manual CCR loader smoke test for local samples"]
fn ccr_loader_smoke() {
    // let path = "./mini_data/20260403T000001Z-mini-a.ccr";
    // let path = "20260403T000101Z-mini-b.ccr";
    let path = "20260403T000201Z-mini-c.ccr";
    let snapshot = load_ccr_snapshot_from_file(fixture_path(path))
        .expect("load CCR snapshot");

    println!("content_type_oid: {}", snapshot.content_type_oid);
    println!("produced_at     : {:?}", snapshot.produced_at);
    println!("vrp_count       : {}", snapshot.vrps.len());
    println!("vap_count       : {}", snapshot.vaps.len());
    println!("first_vrp       : {:?}", snapshot.vrps.first());
    println!("first_vap       : {:?}", snapshot.vaps.first());
    println!("vrps       : {:?}", snapshot.vrps);
    println!("vaps       : {:?}", snapshot.vaps);
}

#[test]
fn find_latest_ccr_file_picks_latest_name() {
    let dir = tempdir().expect("create temp dir");
    let older = dir.path().join("20260324T000037Z-sng1.ccr");
    let newer = dir.path().join("20260324T000138Z-zur1.ccr");
    let ignored = dir.path().join("notes.txt");

    fs::write(&older, b"older").expect("write older ccr");
    fs::write(&newer, b"newer").expect("write newer ccr");
    fs::write(&ignored, b"ignored").expect("write ignored file");

    let latest = find_latest_ccr_file(dir.path()).expect("find latest ccr");

    assert_eq!(latest, newer);
}

#[test]
fn find_latest_ccr_file_picks_latest_date_dir_first() {
    let root = tempdir().expect("create temp root dir");
    let older_dir = root.path().join("20260401");
    let newer_dir = root.path().join("20260402");
    fs::create_dir_all(&older_dir).expect("create older date dir");
    fs::create_dir_all(&newer_dir).expect("create newer date dir");

    let older = older_dir.join("20260401T000001Z-a.ccr");
    let newer = newer_dir.join("20260402T000001Z-b.ccr");
    fs::write(&older, b"older").expect("write older ccr");
    fs::write(&newer, b"newer").expect("write newer ccr");

    let latest = find_latest_ccr_file(root.path()).expect("find latest ccr");
    assert_eq!(latest, newer);
}

#[test]
fn find_latest_ccr_file_skips_latest_empty_dir() {
    let root = tempdir().expect("create temp root dir");
    let older_dir = root.path().join("run_0011");
    let newer_empty_dir = root.path().join("run_0012");
    fs::create_dir_all(&older_dir).expect("create older dir");
    fs::create_dir_all(&newer_empty_dir).expect("create newer empty dir");

    let expected = older_dir.join("20260401T000001Z-a.ccr");
    fs::write(&expected, b"older").expect("write older ccr");

    let latest = find_latest_ccr_file(root.path()).expect("find latest ccr");
    assert_eq!(latest, expected);
}

#[test]
fn snapshot_to_payloads_with_options_skips_invalid_aspa_when_not_strict() {
    let snapshot = ParsedCcrSnapshot {
        content_type_oid: "1.2.840.113549.1.9.16.1.54".to_string(),
        produced_at: Some("20260324000037Z".to_string()),
        vrps: vec![ParsedVrp {
            prefix_addr: "192.0.2.0".parse().expect("parse IPv4"),
            prefix_len: 24,
            max_len: 24,
            asn: 64496,
        }],
        vaps: vec![ParsedAspa {
            customer_asn: 174,
            provider_asns: vec![0],
        }],
    };

    let conversion =
        snapshot_to_payloads_with_options(&snapshot, false).expect("non-strict conversion");

    assert_eq!(conversion.payloads.len(), 1);
    assert!(conversion.invalid_vrps.is_empty());
    assert_eq!(conversion.invalid_vaps.len(), 1);
    assert!(conversion.invalid_vaps[0].contains("provider list must not contain AS0"));
}

#[test]
fn generated_mini_ccr_files_are_parseable() {
    let cases = [
        ("20260403T000001Z-mini-a.ccr", 2usize, 1usize),
        ("20260403T000101Z-mini-b.ccr", 3usize, 1usize),
        ("20260403T000201Z-mini-c.ccr", 2usize, 2usize),
    ];

    for (name, expect_vrps, expect_vaps) in cases {
        let snapshot = load_ccr_snapshot_from_file(fixture_path(name))
            .unwrap_or_else(|e| panic!("failed to parse {}: {:?}", name, e));
        assert_eq!(snapshot.vrps.len(), expect_vrps, "vrp count mismatch for {name}");
        assert_eq!(snapshot.vaps.len(), expect_vaps, "vap count mismatch for {name}");
    }
}
