use anyhow::{bail, Result};
use clap::Args;
use serde::Serialize;
use std::path::Path;
use crate::commands::resolve_symbol;
use crate::core::graph::Graph;
use crate::output::formatter;
use crate::output::json::JsonOutput;
#[derive(Args, Debug)]
pub struct FlowArgs {
pub start: String,
pub end: String,
#[arg(long, default_value = "10")]
pub depth: usize,
#[arg(long, default_value = "5")]
pub limit: usize,
#[arg(long, short = 'j')]
pub json: bool,
}
#[derive(Debug, Serialize)]
pub struct FlowOutput {
pub start: String,
pub end: String,
pub paths: Vec<FlowPath>,
pub total: usize,
pub depth_limit: usize,
}
#[derive(Debug, Serialize)]
pub struct FlowPath {
pub steps: Vec<FlowStep>,
}
#[derive(Debug, Serialize)]
pub struct FlowStep {
pub name: String,
pub file_path: String,
pub line_start: u32,
pub kind: String,
}
pub fn run(args: &FlowArgs, project_root: &Path) -> Result<()> {
let scope_dir = project_root.join(".scope");
if !scope_dir.exists() {
bail!("No .scope/ directory found. Run 'scope init' first.");
}
let db_path = scope_dir.join("graph.db");
if !db_path.exists() {
bail!("No index found. Run 'scope index' to build one first.");
}
let graph = Graph::open(&db_path)?;
crate::commands::warn_if_stale(&graph, project_root);
let start_sym = resolve_symbol(&graph, &args.start)?;
let end_sym = resolve_symbol(&graph, &args.end)?;
let raw_paths =
graph.find_flow_paths(&start_sym.id, &end_sym.id, args.depth, args.limit + 1)?;
let truncated = raw_paths.len() > args.limit;
let total = raw_paths.len();
let raw_paths: Vec<_> = raw_paths.into_iter().take(args.limit).collect();
let paths: Vec<FlowPath> = raw_paths
.into_iter()
.map(|steps| FlowPath {
steps: steps
.into_iter()
.map(|s| FlowStep {
name: s.symbol_name,
file_path: s.file_path,
line_start: s.line,
kind: s.kind,
})
.collect(),
})
.collect();
if args.json {
let output = FlowOutput {
start: args.start.clone(),
end: args.end.clone(),
paths,
total,
depth_limit: args.depth,
};
let json_envelope = JsonOutput {
command: "flow",
symbol: None,
data: &output,
truncated,
total,
};
println!("{}", serde_json::to_string_pretty(&json_envelope)?);
} else {
formatter::print_flow(&args.start, &args.end, &paths, total, args.depth);
}
Ok(())
}