use crate::commands::{self, RezonCommand};
use crate::error::Error::{self, *};
use clap::{command, crate_version, ArgMatches, Command};
use colorful::{Color, Colorful};

pub type App = Command;

pub struct RezonCLI {
	args: ArgMatches,
}

impl RezonCLI {
	pub fn new() -> Self {
		Self {
			args: Self::parse().get_matches(),
		}
	}

	pub async fn run(&self) -> Result<(), Error> {
		if let Some(subcommand) = self.args.subcommand() {
			// Since we did find a sub-command match, let's execute the command
			execute_command(subcommand).await
		} else {
			// If no sub-command was matched, show the help template and return an error
			return Err(InvalidCommand);
		}
	}

	fn parse() -> App {
		let usage = "rezon [SUBCOMMAND] [OPTIONS]";
		command!()
			.allow_external_subcommands(false)
			.disable_colored_help(false)
			.override_usage(usage)
			.long_version(crate_version!())
			.after_help(get_help_postfix())
			.after_long_help(get_help_postfix())
			.subcommands(Self::get_commands())
	}

	fn get_commands() -> Vec<Command> {
		vec![
			commands::init::Init::cmd(),
			commands::deploy::Deploy::cmd(),
			commands::run::Run::cmd(),
			commands::report::Report::cmd(),
		]
	}
}

/// call the corresponding execute function for a given subcommand
async fn execute_command((command_name, args): (&str, &ArgMatches)) -> Result<(), Error> {
	match command_name {
		"init" => commands::init::Init::execute(args).await,
		"deploy" => commands::deploy::Deploy::execute(args).await,
		"run" => commands::run::Run::execute(args).await,
		"report" => commands::report::Report::execute(args).await,
		// clap filters out any incorrect commands when we parse the input
		_ => unreachable!(),
	}
}
fn get_help_postfix() -> String {
	format!(
		"Head over to our docs for more information: {}",
		"https://docs.rezon.ai".color(Color::Purple1a).bold()
	)
}
