use crate::cli::Cli;
use crate::file;
use clap::CommandFactory;
use eyre::Result;
use indoc::formatdoc;
use itertools::Itertools;

/// internal command to generate markdown from help
#[derive(Debug, clap::Args)]
#[clap(hide = true)]
pub struct RenderHelp {}

impl RenderHelp {
    pub fn run(self) -> Result<()> {
        xx::file::mkdirp("docs/.vitepress")?;

        file::write("docs/.vitepress/cli_commands.ts", render_command_ts())?;
        if cfg!(windows) {
            cmd!("prettier.cmd", "--write", "docs/.vitepress/cli_commands.ts").run()?;
        } else {
            cmd!("prettier", "--write", "docs/.vitepress/cli_commands.ts").run()?;
        }
        Ok(())
    }
}

fn render_command_ts() -> String {
    let mut doc = String::new();
    doc.push_str(&formatdoc! {r#"
        // This file is generated by `mise render-help`
        // Do not edit this file directly

        export type Command = {{
          hide: boolean,
          subcommands?: {{
            [key: string]: Command,
          }},
        }};
        "#});
    doc.push_str("export const commands: { [key: string]: Command } = {\n");
    let mut cli = Cli::command()
        .term_width(80)
        .max_term_width(80)
        .disable_help_subcommand(true)
        .disable_help_flag(true);
    for command in cli
        .get_subcommands_mut()
        .sorted_by_cached_key(|c| c.get_name().to_string())
    {
        match command.has_subcommands() {
            true => {
                let name = command.get_name().to_string();
                doc.push_str(&format!(
                    "  \"{}\": {{\n    hide: {},\n    subcommands: {{\n",
                    name,
                    command.is_hide_set()
                ));
                for subcommand in command.get_subcommands_mut() {
                    let output = format!(
                        "      \"{}\": {{\n        hide: {},\n      }},\n",
                        subcommand.get_name(),
                        subcommand.is_hide_set()
                    );
                    doc.push_str(&output);
                }
                doc.push_str("    },\n  },\n");
            }
            false => {
                let output = format!(
                    "  \"{}\": {{\n    hide: {},\n  }},\n",
                    command.get_name(),
                    command.is_hide_set()
                );
                doc.push_str(&output);
            }
        }
    }
    doc.push_str("};\n");
    doc
}
