extern crate self as dioprism_cli;

use std::ffi::OsString;

pub mod assets;
pub mod dioprism;
pub mod dioprism_native_port;
pub mod dxr;
pub mod native_port;
pub mod resume;
pub mod shader;

pub use dioprism::{
    DIOPRISM_CLI_INTEGRATION_RANK_COVERAGE, DioprismCliCommandAdapter,
    DioprismCliIntegrationConfig, DioprismCliRouteOverride, dioprism_cli_batch_payload,
    dioprism_cli_command, dioprism_cli_config,
};

pub fn run_from<I, S>(args: I) -> Result<(), String>
where
    I: IntoIterator<Item = S>,
    S: Into<OsString>,
{
    run(args.into_iter().map(Into::into).collect())
}

pub fn run_dioprism_from<I, S>(args: I) -> Result<(), String>
where
    I: IntoIterator<Item = S>,
    S: Into<OsString>,
{
    dioprism::run_from(args)
}

fn run(mut raw_args: Vec<OsString>) -> Result<(), String> {
    let Some(command) = raw_args.first().cloned() else {
        print_help();
        return Ok(());
    };
    raw_args.remove(0);

    let command = command
        .into_string()
        .map_err(|_| "argument is not valid UTF-8".to_string())?;

    if matches!(command.as_str(), "help" | "--help" | "-h") {
        print_help();
        return Ok(());
    }

    match command.as_str() {
        "dioprism" | "st" | "s" => dioprism::run_from(raw_args),
        "assets" | "asset" | "a" => assets::run_from(os_args_to_strings(raw_args)?),
        "resume" | "res" | "r" => resume::run_from(os_args_to_strings(raw_args)?),
        "shader" | "sh" => shader::run_from(os_args_to_strings(raw_args)?),
        "native-port" | "native" | "n" => native_port::run_from(os_args_to_strings(raw_args)?),
        "dioprism-native-port" | "snp" => {
            dioprism_native_port::run_from(os_args_to_strings(raw_args)?)
        }
        "dxr" => dxr::run_from(os_args_to_strings(raw_args)?),
        "analyze" | "audit" | "plan" | "profile" | "compare" | "manifest" => {
            let mut forwarded = Vec::with_capacity(raw_args.len() + 1);
            forwarded.push(OsString::from(command));
            forwarded.extend(raw_args);
            dioprism::run_from(forwarded)
        }
        other => Err(format!("unknown command `{other}`\n{}", help_text())),
    }
}

pub fn print_help() {
    println!("{}", help_text());
}

pub fn help_text() -> &'static str {
    concat!(
        "dioprism-cli <command> [options]\n\n",
        "Commands:\n",
        "  dioprism | st | s <plan|profile|compare|manifest|analyze|audit> ...\n",
        "  assets | asset | a <css|hash|precompress|budget|routes> ...\n",
        "  resume | res | r route --handler id=/assets/chunk.js#symbol [--out file]\n",
        "  shader | sh render [--preset halo] [--first-paint inline-css]\n",
        "  native-port | native | n <audit|plan|convert|build|verify|doctor> ...\n",
        "  dioprism-native-port | snp <audit|convert> ...\n",
        "  dxr <legacy umbrella command> ...\n"
    )
}

fn os_args_to_strings(args: Vec<OsString>) -> Result<Vec<String>, String> {
    args.into_iter()
        .map(|arg| {
            arg.into_string()
                .map_err(|_| "argument is not valid UTF-8".to_string())
        })
        .collect()
}
