use std::env;

pub fn detect_lang_from_args(args: &[String]) -> Option<String> {
    let mut it = args.iter().skip(1);
    while let Some(arg) = it.next() {
        if arg == "--lang" {
            if let Some(v) = it.next() {
                if !v.trim().is_empty() {
                    return Some(v.to_string());
                }
            }
            continue;
        }
        if let Some(v) = arg.strip_prefix("--lang=") {
            if !v.trim().is_empty() {
                return Some(v.to_string());
            }
        }
    }
    None
}

pub fn locale_from_cli_or_env(cli_lang: Option<&str>) -> String {
    if let Some(lang) = cli_lang {
        return normalize_locale(lang);
    }

    if let Ok(lang) = env::var("TRACK_LANG") {
        if !lang.trim().is_empty() {
            return normalize_locale(&lang);
        }
    }

    if let Ok(lang) = env::var("LANG") {
        if !lang.trim().is_empty() {
            return normalize_locale(&lang);
        }
    }

    "en-US".to_string()
}

pub fn init_i18n(cli_lang: Option<&str>) -> String {
    let locale = locale_from_cli_or_env(cli_lang);
    rust_i18n::set_locale(&locale);
    locale
}

pub fn apply_clap_i18n(cmd: &mut clap::Command, root_key: &str) {
    let new_cmd = apply_clap_i18n_command(cmd.clone(), root_key);
    *cmd = new_cmd;
}

pub fn apply_help_i18n(cmd: &mut clap::Command, root_key: &str, locale: &str) {
    let new_cmd = apply_help_i18n_command(cmd.clone(), root_key, locale, true);
    *cmd = new_cmd;
}

fn normalize_locale(input: &str) -> String {
    let s = input.trim();
    if s.is_empty() {
        return "en-US".to_string();
    }

    let s = s.replace('_', "-");
    let base = s.split('.').next().unwrap_or(&s);
    let base = base.split('@').next().unwrap_or(base);
    let mut parts = base.split('-');
    let lang = parts.next().unwrap_or("en").to_ascii_lowercase();
    let region = parts.next().unwrap_or("US").to_ascii_uppercase();
    format!("{}-{}", lang, region)
}

fn apply_clap_i18n_command(mut cmd: clap::Command, key_prefix: &str) -> clap::Command {
    if let Some(v) = lookup(&format!("{key_prefix}.about")) {
        cmd = cmd.about(v);
    }
    if let Some(v) = lookup(&format!("{key_prefix}.long_about")) {
        cmd = cmd.long_about(v);
    }
    if let Some(v) = lookup(&format!("{key_prefix}.after_help")) {
        cmd = cmd.after_help(v);
    }
    if let Some(v) = lookup(&format!("{key_prefix}.before_help")) {
        cmd = cmd.before_help(v);
    }

    let arg_ids: Vec<String> = cmd
        .get_arguments()
        .map(|a| a.get_id().to_string())
        .collect();
    for arg_id in arg_ids {
        if let Some(v) = lookup(&format!("{key_prefix}.args.{arg_id}")) {
            cmd = cmd.mut_arg(arg_id.clone(), |a| a.help(v)).clone();
        }
        if let Some(v) = lookup(&format!("{key_prefix}.args_long.{arg_id}")) {
            cmd = cmd.mut_arg(arg_id.clone(), |a| a.long_help(v)).clone();
        }
    }

    let sub_names: Vec<String> = cmd
        .get_subcommands()
        .map(|s| s.get_name().to_string())
        .collect();
    for name in sub_names {
        let child_key = format!("{key_prefix}.commands.{name}");
        cmd = cmd
            .mut_subcommand(name, |sub| apply_clap_i18n_command(sub, &child_key))
            .clone();
    }

    cmd
}

fn apply_help_i18n_command(
    mut cmd: clap::Command,
    root_key: &str,
    locale: &str,
    is_root: bool,
) -> clap::Command {
    let help_key = format!("{root_key}.help");
    let mut template = String::new();
    template.push_str("{about}\n\n");

    let usage_title = lookup(&format!("{help_key}.usage")).unwrap_or_else(|| "Usage".to_string());
    template.push_str(&format!("{usage_title}: {{usage}}\n\n"));

    let commands_title =
        lookup(&format!("{help_key}.commands")).unwrap_or_else(|| "Commands".to_string());
    template.push_str(&format!("{commands_title}:\n{{subcommands}}\n\n"));

    let options_title =
        lookup(&format!("{help_key}.options")).unwrap_or_else(|| "Options".to_string());
    template.push_str(&format!("{options_title}:\n{{options}}\n"));

    cmd = cmd.help_template(template).disable_help_subcommand(true);

    let is_zh = locale.to_ascii_lowercase().starts_with("zh");
    let help_short = if is_zh {
        "显示帮助信息"
    } else {
        "Print help"
    };
    let help_long = if is_zh {
        "显示帮助信息(使用 '-h' 查看摘要)"
    } else {
        "Print help (see a summary with '-h')"
    };
    let version_short = if is_zh {
        "显示版本信息"
    } else {
        "Print version"
    };

    cmd = cmd.disable_help_flag(true);

    let arg_ids: Vec<String> = cmd
        .get_arguments()
        .map(|a| a.get_id().to_string())
        .collect();

    if !arg_ids.iter().any(|id| id == "help") {
        cmd = cmd.arg(
            clap::Arg::new("help")
                .short('h')
                .long("help")
                .action(clap::ArgAction::Help)
                .global(true)
                .help(help_short)
                .long_help(help_long),
        );
    } else {
        cmd = cmd
            .mut_arg("help", |a| a.help(help_short).long_help(help_long))
            .clone();
    }

    if is_root {
        cmd = cmd.disable_version_flag(true);
        if !arg_ids.iter().any(|id| id == "version") {
            cmd = cmd.arg(
                clap::Arg::new("version")
                    .short('V')
                    .long("version")
                    .action(clap::ArgAction::Version)
                    .help(version_short)
                    .long_help(version_short),
            );
        } else {
            cmd = cmd
                .mut_arg("version", |a| {
                    a.help(version_short).long_help(version_short)
                })
                .clone();
        }
    }

    let sub_names: Vec<String> = cmd
        .get_subcommands()
        .map(|s| s.get_name().to_string())
        .collect();
    for name in sub_names {
        cmd = cmd
            .mut_subcommand(name, |sub| {
                apply_help_i18n_command(sub, root_key, locale, false)
            })
            .clone();
    }

    cmd
}

fn lookup(key: &str) -> Option<String> {
    let v = t!(key);
    if v.as_ref() == key {
        None
    } else {
        Some(v.to_string())
    }
}