mod cli;
mod config;
mod daemon;
mod ipc;
mod scheduler;
mod state;

use clap::{Parser, Subcommand};
use muzan::DaemonCommand;

#[derive(Parser)]
#[command(name = "koku", about = "cron daemon — 刻")]
struct Cli {
	#[command(subcommand)]
	command: Commands,
}

#[derive(Subcommand)]
enum Commands {
	/// Scaffold a config file with examples
	Init,
	/// Validate config and preview next-run times
	Check,
	/// Daemon lifecycle management
	Daemon {
		#[command(subcommand)]
		command: DaemonCommand,
	},
	/// Show job status
	Status {
		/// Output as JSON
		#[arg(long)]
		json: bool,
	},
	/// Trigger a one-off run
	Run {
		/// Job name
		name: String,
	},
	/// Pause a job
	Pause {
		/// Job name
		name: String,
	},
	/// Resume a paused or stopped job
	Resume {
		/// Job name
		name: String,
	},
	/// Reload config without restarting
	Reload,
}

fn main() {
	let cli = Cli::parse();

	match cli.command {
		Commands::Init => cli::init(),
		Commands::Check => cli::check(),

		Commands::Daemon { command } => {
			match command {
				DaemonCommand::Run => {
					tracing_subscriber::fmt()
						.with_env_filter(
							tracing_subscriber::EnvFilter::from_default_env()
								.add_directive(tracing::Level::INFO.into()),
						)
						.init();

					let config_path = config::Config::default_path();
					let config = match config::Config::load(&config_path) {
						Ok(c) => c,
						Err(e) => {
							eprintln!("error: {}", e);
							std::process::exit(1);
						}
					};

					let errors = config.validate();
					if !errors.is_empty() {
						for e in &errors {
							eprintln!("error: {}", e);
						}
						std::process::exit(1);
					}

					let rt = tokio::runtime::Runtime::new().unwrap();
					rt.block_on(daemon::run(config));
				}
				other => {
					let paths = muzan::DaemonPaths::new("koku");
					other.execute(&paths);
				}
			}
		}

		Commands::Status { json } => cli::status(json),
		Commands::Run { name } => cli::send_command(ipc::Request::Run(name)),
		Commands::Pause { name } => cli::send_command(ipc::Request::Pause(name)),
		Commands::Resume { name } => cli::send_command(ipc::Request::Resume(name)),
		Commands::Reload => cli::send_command(ipc::Request::Reload),
	}
}
