use rpki::audit_trace::trace_rule_to_root;
use rpki::storage::{AuditRuleKind, RocksStore, VcirOutputType};
use serde_json::Value;
use std::env;
use std::path::Path;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        eprintln!("usage: trace_arin_missing_vrps <db> <row> [<row> ...]");
        std::process::exit(2);
    }

    let store = RocksStore::open(Path::new(&args[1])).expect("open db");
    let vcirs = store.list_vcirs().expect("list vcirs");

    for row in &args[2..] {
        let parts: Vec<&str> = row.split(',').collect();
        if parts.len() != 4 {
            println!("ROW {row}");
            println!("ERROR invalid compare row");
            println!();
            continue;
        }
        let asn: u32 = parts[0]
            .trim_start_matches("AS")
            .parse()
            .expect("parse asn");
        let prefix = parts[1].to_string();
        let max_length: u8 = parts[2].parse().expect("parse max length");
        let mut found = false;

        println!("ROW {row}");
        for vcir in &vcirs {
            for output in &vcir.local_outputs {
                if output.output_type != VcirOutputType::Vrp {
                    continue;
                }
                let payload: Value = match serde_json::from_str(&output.payload_json) {
                    Ok(value) => value,
                    Err(_) => continue,
                };
                let payload_asn = payload
                    .get("asn")
                    .and_then(|v| v.as_u64())
                    .map(|v| v as u32);
                let payload_prefix = payload
                    .get("prefix")
                    .and_then(|v| v.as_str())
                    .map(|v| v.to_string());
                let payload_max = payload
                    .get("max_length")
                    .and_then(|v| v.as_u64())
                    .map(|v| v as u8);
                if payload_asn == Some(asn)
                    && payload_prefix.as_ref() == Some(&prefix)
                    && payload_max == Some(max_length)
                {
                    found = true;
                    println!("manifest_rsync_uri={}", vcir.manifest_rsync_uri);
                    println!("source_object_uri={}", output.source_object_uri);
                    println!("source_object_hash={}", output.source_object_hash);
                    println!("source_ee_cert_hash={}", output.source_ee_cert_hash);
                    println!("rule_hash={}", output.rule_hash);
                    println!("validation_path_hint={:?}", output.validation_path_hint);

                    if let Some(trace) =
                        trace_rule_to_root(&store, AuditRuleKind::Roa, &output.rule_hash)
                            .expect("trace rule")
                    {
                        println!(
                            "trace_leaf_manifest={}",
                            trace
                                .chain_leaf_to_root
                                .first()
                                .map(|node| node.manifest_rsync_uri.as_str())
                                .unwrap_or("")
                        );
                        println!(
                            "trace_source_object_uri={}",
                            trace.resolved_output.source_object_uri
                        );
                        println!("trace_chain_len={}", trace.chain_leaf_to_root.len());
                        for (idx, node) in trace.chain_leaf_to_root.iter().enumerate() {
                            println!("chain[{idx}].manifest={}", node.manifest_rsync_uri);
                            println!(
                                "chain[{idx}].current_manifest={}",
                                node.current_manifest_rsync_uri
                            );
                            println!("chain[{idx}].current_crl={}", node.current_crl_rsync_uri);
                        }
                    }
                    println!();
                }
            }
        }

        if !found {
            println!("NOT_FOUND");
            println!();
        }
    }
}
