use std::path::PathBuf;

use clap::Args;
use clap::Parser;
use clap::Subcommand;
use clap::ValueEnum;

use crate::please_release::run_release_please;

#[derive(Parser, Clone)]
#[command(author, version, about, long_about = None, subcommand_required = true)]
pub struct Command {
    #[command(subcommand)]
    commands: Commands,

    #[command(flatten)]
    global: GlobalArgs,
}

#[derive(Subcommand, Clone)]
pub enum Commands {
    #[command(subcommand_required = true)]
    Local {
        #[command(subcommand)]
        command: LocalCommands,
    },
    PullRequest {},
    Main {},
    Release,
}

#[derive(Subcommand, Clone)]
pub enum LocalCommands {
    Test,
    PleaseRelease,
}

#[derive(Debug, Clone, ValueEnum)]
pub enum BuildProfile {
    Debug,
    Release,
}

#[derive(Debug, Clone, Args)]
pub struct GlobalArgs {
    #[arg(long, global = true, help_heading = "Global")]
    dry_run: bool,

    #[arg(long, global = true, help_heading = "Global")]
    rust_builder_image: Option<String>,

    #[arg(long, global = true, help_heading = "Global")]
    cuddle_please_image: Option<String>,

    #[arg(long, global = true, help_heading = "Global")]
    source: Option<PathBuf>,
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
    let _ = dotenv::dotenv();
    let _ = color_eyre::install();

    let cli = Command::parse();

    let client = dagger_sdk::connect().await?;

    match &cli.commands {
        Commands::Local { command } => match command {
            LocalCommands::Test => {
                test::execute(client, &cli.global).await?;
            }
            LocalCommands::PleaseRelease => todo!(),
        },
        Commands::PullRequest {} => {
            async fn test(client: dagger_sdk::Query, cli: &Command) {
                let args = &cli.global;

                test::execute(client.clone(), args).await.unwrap();
            }

            tokio::join!(test(client.clone(), &cli),);
        }
        Commands::Main {} => {
            async fn test(client: dagger_sdk::Query, cli: &Command) {
                let args = &cli.global;

                test::execute(client.clone(), args).await.unwrap();
            }

            async fn cuddle_please(client: dagger_sdk::Query, cli: &Command) {
                run_release_please(client.clone(), &cli.global)
                    .await
                    .unwrap();
            }

            tokio::join!(
                test(client.clone(), &cli),
                cuddle_please(client.clone(), &cli)
            );
        }
        Commands::Release => {}
    }

    Ok(())
}

mod please_release {

    use dagger_cuddle_please::{models::CuddlePleaseSrcArgs, DaggerCuddlePleaseAction};

    use crate::GlobalArgs;

    pub async fn run_release_please(
        client: dagger_sdk::Query,
        args: &GlobalArgs,
    ) -> eyre::Result<()> {
        DaggerCuddlePleaseAction::dagger(client)
            .execute_src(&CuddlePleaseSrcArgs {
                cuddle_image: args
                    .cuddle_please_image
                    .clone()
                    .unwrap_or("kasperhermansen/cuddle-please:latest".into()),
                server: dagger_cuddle_please::models::SrcServer::Gitea {
                    token: std::env::var("CUDDLE_PLEASE_TOKEN")
                        .expect("CUDDLE_PLEASE_TOKEN to be present"),
                },
                log_level: Some(dagger_cuddle_please::models::LogLevel::Debug),
            })
            .await?;

        Ok(())
    }
}

mod test {
    use std::path::PathBuf;

    use dagger_rust::build::RustVersion;

    use crate::GlobalArgs;

    pub async fn execute(client: dagger_sdk::Query, _args: &GlobalArgs) -> eyre::Result<()> {
        dagger_rust::test::RustTest::new(client)
            .test(
                None::<PathBuf>,
                RustVersion::Nightly,
                &["crates/*", "examples/*", "ci"],
                &[],
            )
            .await?;

        Ok(())
    }
}
