use std::path::PathBuf;

use clap::Parser;
use serde::Serialize;

use super::{AmbientError, Config, Leaf};
use ambient_ci::{
    project::{ProjectError, Projects},
    runlog::RunLog,
};

#[derive(Debug, Parser)]
pub struct ProjectsCmd {
    #[clap(long)]
    oneline: bool,

    /// Name of YAML file with projects.
    #[clap(long)]
    projects: Option<PathBuf>,
}

impl Leaf for ProjectsCmd {
    fn run(&self, config: &Config, _runlog: &mut RunLog) -> Result<(), AmbientError> {
        let projects = if let Some(filename) = &self.projects {
            filename.to_path_buf()
        } else {
            config.projects().into()
        };

        let projects = Projects::from_file(&projects)
            .map_err(|err| ProjectsCmdError::FromFile(projects, err))?;

        config.lint(&projects)?;

        let mut names: Vec<String> = projects.iter().map(|(name, _)| name.to_string()).collect();
        names.sort();

        let list = ProjectsList { projects: names };

        let json = if self.oneline {
            serde_json::to_string(&list).map_err(ProjectsCmdError::ToJson)?
        } else {
            serde_json::to_string_pretty(&list).map_err(ProjectsCmdError::ToJson)?
        };

        println!("{json}");

        Ok(())
    }
}

#[derive(Serialize)]
struct ProjectsList {
    projects: Vec<String>,
}

#[derive(Debug, thiserror::Error)]
pub enum ProjectsCmdError {
    #[error("failed to load project list from file {0}")]
    FromFile(PathBuf, #[source] ProjectError),

    #[error("failed to serialize project list to JSON")]
    ToJson(#[source] serde_json::Error),
}
