use crate::cli::Cli;
use crate::file;
use clap::{Command, 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())
    {
        doc.push_str(&render_command(command, 2));
    }
    doc.push_str("};\n");
    doc
}

fn render_command(command: &mut Command, indent: usize) -> String {
    let pad = " ".repeat(indent);
    let mut output = format!(
        "{pad}\"{}\": {{\n{pad}  hide: {},\n",
        command.get_name(),
        command.is_hide_set()
    );
    if command.has_subcommands() {
        output.push_str(&format!("{pad}  subcommands: {{\n"));
        for subcommand in command
            .get_subcommands_mut()
            .sorted_by_cached_key(|c| c.get_name().to_string())
        {
            output.push_str(&render_command(subcommand, indent + 4));
        }
        output.push_str(&format!("{pad}  }},\n"));
    }
    output.push_str(&format!("{pad}}},\n"));
    output
}
