use std::path::PathBuf;

use clap::Parser;
use south::error::{SouthError, SouthResult};

use crate::{
    cli::{
        handle_south_add, handle_south_clone, handle_south_forall, handle_south_init,
        handle_south_new, handle_south_update,
    },
    config::{ConfigOperations, handle_config_operations},
};

mod cli;
mod config;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
enum Cli {
    /// Create a new south workspace - run this
    /// from your project's root directory
    New {
        #[arg(short, long)]
        project_dir: Option<PathBuf>,
    },

    /// Initialize a south workspace from an existing
    /// project directory containing south.yaml
    Init {
        #[arg(short, long)]
        project_dir: Option<PathBuf>,
    },

    /// Add a repo to your south manifest
    AddRepo {
        #[arg(short, long)]
        url: String,
    },

    /// Initialize a south workspace from remote
    /// - by cloning an existing south project
    /// and workspace
    Clone {
        #[arg(short, long)]
        url: String,
    },

    /// Update South config
    #[command(subcommand)]
    Config(ConfigOperations),

    /// Updates all of the repositories that your
    /// south project depends on to their respective
    /// commit as specified in south.yaml
    Update,

    /// Run a command across all repositories
    /// in the south manifest
    ForAll {
        /// Command to run
        #[arg(short, long)]
        command: String,
    },
}

fn main() -> SouthResult<()> {
    let cli = Cli::parse();

    let mut config_manager = config::ConfigManager::new()?;

    // Commands that require an active workspace
    let requires_workspace = matches!(
        cli,
        Cli::Update | Cli::AddRepo { .. } | Cli::ForAll { .. }
    );

    if requires_workspace && config_manager.get_active_config().is_none() {
        return Err(SouthError::ConfigurationError(
            "No active south workspace found. Run `south new` or `south init` first".to_string(),
        ));
    }

    match cli {
        Cli::New { project_dir } => handle_south_new(project_dir, &mut config_manager),
        Cli::Init { project_dir } => handle_south_init(project_dir, &mut config_manager),
        Cli::AddRepo { url } => handle_south_add(&url, &mut config_manager),
        Cli::Clone { url } => handle_south_clone(&url, &mut config_manager),
        Cli::Update => handle_south_update(&config_manager),
        Cli::Config(config_ops) => handle_config_operations(config_ops, &mut config_manager),
        Cli::ForAll { command } => handle_south_forall(&command, &config_manager),
    }
}
