use std::path::PathBuf;

fn usage() -> &'static str {
    "Usage: cir_extract_inputs --cir <path> --tals-dir <path> --meta-json <path>"
}

fn main() {
    if let Err(err) = run(std::env::args().collect()) {
        eprintln!("error: {err}");
        std::process::exit(2);
    }
}

fn run(argv: Vec<String>) -> Result<(), String> {
    let mut cir_path: Option<PathBuf> = None;
    let mut tals_dir: Option<PathBuf> = None;
    let mut meta_json: Option<PathBuf> = None;

    let mut i = 1usize;
    while i < argv.len() {
        match argv[i].as_str() {
            "--help" | "-h" => return Err(usage().to_string()),
            "--cir" => {
                i += 1;
                cir_path = Some(PathBuf::from(argv.get(i).ok_or("--cir requires a value")?));
            }
            "--tals-dir" => {
                i += 1;
                tals_dir = Some(PathBuf::from(
                    argv.get(i).ok_or("--tals-dir requires a value")?,
                ));
            }
            "--meta-json" => {
                i += 1;
                meta_json = Some(PathBuf::from(
                    argv.get(i).ok_or("--meta-json requires a value")?,
                ));
            }
            other => return Err(format!("unknown argument: {other}\n\n{}", usage())),
        }
        i += 1;
    }

    let cir_path = cir_path.ok_or_else(|| format!("--cir is required\n\n{}", usage()))?;
    let tals_dir = tals_dir.ok_or_else(|| format!("--tals-dir is required\n\n{}", usage()))?;
    let meta_json = meta_json.ok_or_else(|| format!("--meta-json is required\n\n{}", usage()))?;

    let bytes = std::fs::read(&cir_path)
        .map_err(|e| format!("read CIR failed: {}: {e}", cir_path.display()))?;
    let cir = rpki::cir::decode_cir(&bytes).map_err(|e| e.to_string())?;

    std::fs::create_dir_all(&tals_dir).map_err(|e| {
        format!(
            "create trust_anchors dir failed: {}: {e}",
            tals_dir.display()
        )
    })?;

    let mut tal_files = Vec::new();
    for (idx, tal) in cir.trust_anchors.iter().enumerate() {
        let filename = format!("tal-{:03}.tal", idx + 1);
        let path = tals_dir.join(filename);
        std::fs::write(&path, &tal.tal_bytes)
            .map_err(|e| format!("write TAL failed: {}: {e}", path.display()))?;
        tal_files.push(serde_json::json!({
            "talUri": tal.tal_uri,
            "taRsyncUri": tal.ta_rsync_uri,
            "taCertificateSha256": hex::encode(&tal.ta_certificate_sha256),
            "path": path,
        }));
    }

    let validation_time = cir
        .validation_time
        .format(&time::format_description::well_known::Rfc3339)
        .map_err(|e| format!("format validationTime failed: {e}"))?;
    let meta = serde_json::json!({
        "validationTime": validation_time,
        "trustAnchorCount": cir.trust_anchors.len(),
        "talFiles": tal_files,
    });
    if let Some(parent) = meta_json.parent() {
        std::fs::create_dir_all(parent)
            .map_err(|e| format!("create meta parent failed: {}: {e}", parent.display()))?;
    }
    std::fs::write(&meta_json, serde_json::to_vec_pretty(&meta).unwrap())
        .map_err(|e| format!("write meta json failed: {}: {e}", meta_json.display()))?;
    Ok(())
}
