use clap::Args;
use sp_core::crypto::Ss58AddressFormat;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ParseError;

impl std::fmt::Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "failed to parse network value as u16")
    }
}

impl std::error::Error for ParseError {}

static ALL_POSSIBLE_NAMES: [&str; 2] = ["ghost", "casper"];
static ALL_POSSIBLE_IDS: [u16; 2] = [1995, 1996];

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct InnerSs58AddressFormat(Ss58AddressFormat);

impl InnerSs58AddressFormat {
    #[inline]
    pub fn custom(prefix: u16) -> Self {
        Self {
            0: Ss58AddressFormat::custom(prefix),
        }
    }
}

impl std::fmt::Display for InnerSs58AddressFormat {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "{} network",
            ALL_POSSIBLE_IDS
                .binary_search(&u16::from(self.0))
                .expect("always be found")
        )
    }
}

impl<'a> TryFrom<&'a str> for InnerSs58AddressFormat {
    type Error = ParseError;

    fn try_from(x: &'a str) -> Result<Self, Self::Error> {
        match ALL_POSSIBLE_NAMES.iter().position(|&n| n == x) {
            Some(id) => Ok(InnerSs58AddressFormat::custom(ALL_POSSIBLE_IDS[id])),
            _ => Err(ParseError),
        }
    }
}

pub fn parse_s58_prefix_address_format(x: &str) -> Result<Ss58AddressFormat, String> {
    match InnerSs58AddressFormat::try_from(x) {
        Ok(format_registry) => Ok(format_registry.0.into()),
        Err(_) => Err(format!(
            "Unable to parse variant. Known variants: {:?}",
            &ALL_POSSIBLE_NAMES
        )),
    }
}

/// Optional flag for specifying network scheme
#[derive(Debug, Clone, Args)]
pub struct NetworkSchemeFlag {
    /// Network address format
    #[arg(
        short = 'n',
        long,
        ignore_case = true,
        value_parser = parse_s58_prefix_address_format,
        value_name = "NETWORK",
        default_value = "casper",
    )]
    pub network: Option<Ss58AddressFormat>,
}
