//! `ckg cross-repo-edges` — list registry repos and CROSS_CALLS edges.
//! `--resolve` re-runs the qname-match pass and writes new CROSS_CALLS rows.
use std::collections::BTreeMap;
use std::path::PathBuf;

use anyhow::Result;
use ckg_storage::RegistryStorage;
use clap::Args as ClapArgs;
use cozo::{DataValue, ScriptMutability};

#[derive(ClapArgs, Debug)]
pub struct Args {
    /// Filter to a specific repo_id.
    #[arg(long)]
    pub repo: Option<String>,
    /// Run the qname-match pass to populate CROSS_CALLS.
    #[arg(long)]
    pub resolve: bool,
    /// Maximum CROSS_CALLS rows to print.
    #[arg(long, default_value_t = 50)]
    pub limit: u32,
}

pub fn run(home: Option<PathBuf>, args: Args) -> Result<()> {
    let base = crate::ckg_home(home)?;

    if args.resolve {
        let n = ckg_resolve::resolve_cross_repo(&base)?;
        println!("wrote {n} CROSS_CALLS rows");
    }

    let registry = RegistryStorage::open(&base)?;
    let repos = registry.list_repos()?;
    if repos.is_empty() {
        println!("(no repos registered — run `ckg index <path>` first)");
        return Ok(());
    }
    println!("{} registered repos:", repos.len());
    for (id, root, head) in &repos {
        if let Some(filter) = &args.repo
            && filter != id
        {
            continue;
        }
        let head_short = if head.len() >= 8 { &head[..8] } else { head };
        println!("  {id}  {head_short:<10}  {root}");
    }

    for rel in &["CROSS_CALLS", "CROSS_IMPORTS", "CROSS_EXTENDS"] {
        // IM4 fix: this is a read-only query — Cozo's Mutable mode
        // takes a write lock unnecessarily. Use Immutable so the query
        // doesn't contend with concurrent writes.
        let edges = registry
            .db()
            .run_script(
                &format!(
                    "?[src, dst, confidence] := *{rel}{{src, dst, confidence}} :limit {}",
                    args.limit.max(1)
                ),
                BTreeMap::new(),
                ScriptMutability::Immutable,
            )
            .map_err(|e| anyhow::anyhow!("{e}"))?;
        println!("\n{rel} edges: {}", edges.rows.len());
        // L3: .take() is redundant — the Cozo `:limit` already caps rows.
        for row in &edges.rows {
            if let (Some(DataValue::Str(s)), Some(DataValue::Str(d))) = (row.first(), row.get(1)) {
                println!("  {s} -> {d}");
            }
        }
    }
    Ok(())
}
