pub mod report;

use super::{
    NnsCommandError, OutputFormat,
    leaf::{self, NnsCommonOptions},
    now_unix_secs, write_text_or_json,
};
use crate::{
    cli::{
        clap::{parse_matches, parse_required_subcommand, passthrough_subcommand, render_help},
        help::{print_help_or_version, print_help_or_version_flag},
    },
    nns::registry::report::{
        DEFAULT_NNS_REGISTRY_SOURCE_ENDPOINT, NnsRegistryVersionRequest,
        build_nns_registry_version_report, nns_registry_version_report_text,
    },
    version_text,
};
use clap::Command as ClapCommand;
use std::ffi::OsString;

const REGISTRY_VERSION_HELP_AFTER: &str = "\
Examples:
  icq nns registry version
  icq --network ic nns registry version --format json
  icq nns registry version --source-endpoint https://icp-api.io";

///
/// RegistryVersionOptions
///
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) struct RegistryVersionOptions {
    pub(super) network: String,
    pub(super) format: OutputFormat,
    pub(super) source_endpoint: String,
}

pub(super) fn run<I>(args: I) -> Result<(), NnsCommandError>
where
    I: IntoIterator<Item = OsString>,
{
    let args = args.into_iter().collect::<Vec<_>>();
    if print_help_or_version_flag(&args, registry_usage, version_text()) {
        return Ok(());
    }
    let (command, args) = parse_required_subcommand(registry_command(), args)
        .map_err(|_| NnsCommandError::Usage(registry_usage()))?;

    match command.as_str() {
        "version" => run_registry_version(args),
        _ => unreachable!("nns registry dispatch command only defines known commands"),
    }
}

fn run_registry_version<I>(args: I) -> Result<(), NnsCommandError>
where
    I: IntoIterator<Item = OsString>,
{
    let args = args.into_iter().collect::<Vec<_>>();
    if print_help_or_version(&args, registry_version_usage, version_text()) {
        return Ok(());
    }
    let options = RegistryVersionOptions::parse(args)?;
    let request = NnsRegistryVersionRequest {
        network: options.network,
        source_endpoint: options.source_endpoint,
        now_unix_secs: now_unix_secs()?,
    };
    let report = build_nns_registry_version_report(&request)?;
    write_text_or_json(options.format, &report, nns_registry_version_report_text)
}

impl RegistryVersionOptions {
    pub(super) fn parse<I>(args: I) -> Result<Self, NnsCommandError>
    where
        I: IntoIterator<Item = OsString>,
    {
        let matches = parse_matches(registry_version_command(), args)
            .map_err(|_| NnsCommandError::Usage(registry_version_usage()))?;
        let common = NnsCommonOptions::from_matches(&matches);
        Ok(Self {
            network: common.network,
            format: common.format,
            source_endpoint: common.source_endpoint,
        })
    }
}

pub(super) fn registry_command() -> ClapCommand {
    ClapCommand::new("registry")
        .bin_name("icq nns registry")
        .about("Inspect NNS registry metadata")
        .disable_help_flag(true)
        .subcommand(passthrough_subcommand(
            ClapCommand::new("version").about("Show the latest mainnet NNS registry version"),
        ))
}

fn registry_version_command() -> ClapCommand {
    ClapCommand::new("version")
        .bin_name("icq nns registry version")
        .about("Show the latest mainnet NNS registry version")
        .disable_help_flag(true)
        .arg(leaf::format_arg())
        .arg(
            leaf::source_endpoint_arg(DEFAULT_NNS_REGISTRY_SOURCE_ENDPOINT)
                .help("IC API endpoint used for the native NNS registry query"),
        )
        .arg(leaf::network_arg())
        .after_help(REGISTRY_VERSION_HELP_AFTER)
}

pub(super) fn registry_usage() -> String {
    render_help(registry_command())
}

pub(super) fn registry_version_usage() -> String {
    render_help(registry_version_command())
}
