use std::ffi::OsStr;
use clap::{arg, Command, ArgMatches, Id};
use std::path::PathBuf;
use clap::builder::{EnumValueParser, PathBufValueParser, ValueParser};
use clap_complete::{ArgValueCompleter, CompletionCandidate, ValueHint};
use crate::cli::completers;
use treeflow::core::config::Config;
use treeflow::utils::Shell;
pub fn command(config: &Config) -> Command {
Command::new("treeflow")
.version(env!("CARGO_PKG_VERSION"))
.subcommands(subcommands(config))
.subcommand_required(true)
}
pub fn subcommands(config: &Config) -> Vec<Command> {
let mut commands = vec![
Command::new("config")
.about("Prints the current configuration to the screen."),
Command::new("init")
.about("Prints the shell function used to initialise treeflow.")
.arg(arg!(<SHELL>).value_parser(EnumValueParser::<Shell>::new()).help("Shell to initialise for"))
.arg(arg!(--"enable-shorthands").short('s').help("Enable shell aliases for treeflow commands")),
Command::new("worktype")
.about("Manage work types.")
.subcommands(worktype_commands()),
Command::new("project")
.about("Manage a project")
.subcommands(project_commands()),
Command::new("primary")
.about("Navigate to the primary repository directory.")
];
commands.extend(start_on_work_type_commands(config));
commands.extend(vec![
Command::new("review")
.about("Review an existing branch as a worktree.")
.arg(arg!(<BRANCH>).add(ArgValueCompleter::new(completers::branches)).help("Branch to review")),
Command::new("finish")
.about("Finish a piece of work and remove the associated worktree and move back to the main repository.")
.arg(arg!(--force).short('f').help("Force removal of worktree even if it contains untracked files")),
]);
commands
}
fn worktype_commands() -> Vec<Command> {
vec![
Command::new("list")
.about("List all configured work types."),
Command::new("add")
.about("Add a new type of work")
.arg(arg!(<NAME>).add(ArgValueCompleter::new(completers::worktypes)).help("Name of the type of work"))
.arg(arg!(--prefix <PREFIX>).short('p').required(true).help("Prefix to branches for some work")),
Command::new("remove")
.about("Remove a work type")
.arg(arg!(<NAME>).add(ArgValueCompleter::new(completers::worktypes)).help("Name of the type of work to remove")),
]
}
fn project_commands() -> Vec<Command> {
vec![
Command::new("list")
.about("List all configured projects"),
Command::new("add")
.about("Add a repository as a treeflow project")
.arg(arg!(<REPOSITORY_DIR>).value_parser(PathBufValueParser::new()).value_hint(ValueHint::DirPath).help("Path to repository"))
.arg(arg!(--"worktrees-dir" <PATH>).short('d').value_parser(PathBufValueParser::new()).value_hint(ValueHint::DirPath).help("Path to directory where worktrees are stored for a project")),
Command::new("remove")
.about("Remove a project from the configuration")
.arg(arg!(<REPOSITORY_DIR>).value_parser(PathBufValueParser::new()).value_hint(ValueHint::DirPath).help("Path to repository")),
]
}
fn start_on_work_type_commands(config: &Config) -> Vec<Command> {
config.work_types.iter()
.map(|work_type| {
let static_name: &'static str = Box::leak(work_type.type_name.clone().into_boxed_str());
let static_prefix: &'static str = Box::leak(work_type.prefix.clone().into_boxed_str());
let work_names = |current: &OsStr| -> Vec<CompletionCandidate> { completers::work_names(current, static_prefix) };
Command::new(static_name)
.about(format!("Start a {} work item.", static_name))
.arg(arg!(<NAME>).help("Name of the work to begin").add(ArgValueCompleter::new(work_names)))
})
.collect()
}