use alloc::format;
use core::{cmp, fmt};
#[derive(Debug)]
pub struct InformantLine<'a> {
                    pub enable_colors: bool,
        pub chain_name: &'a str,
        pub relay_chain: Option<RelayChain<'a>>,
        pub max_line_width: u32,
        pub num_peers: u64,
        pub num_network_connections: u64,
        pub network_known_best: Option<u64>,
        pub best_number: u64,
        pub best_hash: &'a [u8],
        pub finalized_number: u64,
        pub finalized_hash: &'a [u8],
}
#[derive(Debug)]
pub struct RelayChain<'a> {
        pub chain_name: &'a str,
        pub best_number: u64,
}
impl<'a> fmt::Display for InformantLine<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                
                let cyan = if self.enable_colors { "\x1b[36m" } else { "" };
        let white_bold = if self.enable_colors { "\x1b[1;37m" } else { "" };
        let light_gray = if self.enable_colors { "\x1b[90m" } else { "" };
        let reset = if self.enable_colors { "\x1b[0m" } else { "" };
        let (header, header_len) = if let Some(relay_chain) = &self.relay_chain {
            let header = format!(
                "    {cyan}{chain_name}{reset}   {white_bold}{local_best:<10}{reset} {light_gray}({relay_chain_name} {relay_best}){reset} [",
                cyan = cyan,
                reset = reset,
                white_bold = white_bold,
                light_gray = light_gray,
                chain_name = self.chain_name,
                relay_chain_name = relay_chain.chain_name,
                local_best = BlockNumberDisplay(self.best_number),
                relay_best = BlockNumberDisplay(relay_chain.best_number),
            );
            let header_len = self.chain_name.chars().count() + relay_chain.chain_name.len() + 29;             (header, header_len)
        } else {
            let header = format!(
                "    {cyan}{chain_name}{reset}   {white_bold}{local_best:<10}{reset} [",
                cyan = cyan,
                reset = reset,
                white_bold = white_bold,
                chain_name = self.chain_name,
                local_best = BlockNumberDisplay(self.best_number),
            );
            let header_len = self.chain_name.chars().count() + 19;             (header, header_len)
        };
                let trailer = format!(
            "] {white_bold}{network_best}{reset} (🔗{white_bold}{peers:>3}{reset}) (🌐{white_bold}{connec:>4}{reset})   ",
            network_best = self
                .network_known_best
                .map(BlockNumberDisplay)
                .map_or(either::Right("?"), either::Left),
            peers = self.num_network_connections,
            connec = self.num_network_connections,
            white_bold = white_bold,
            reset = reset,
        );
        let trailer_len = format!(
            "] {network_best} (  {peers:>3}) (  {connec:>4})   ",
            network_best = self
                .network_known_best
                .map(BlockNumberDisplay)
                .map(either::Left)
                .unwrap_or(either::Right("?")),
            peers = self.num_network_connections,
            connec = self.num_network_connections,
        )
        .len();
        let bar_width = self
            .max_line_width
            .saturating_sub(u32::try_from(header_len).unwrap())
            .saturating_sub(u32::try_from(trailer_len).unwrap());
        let actual_network_best = cmp::max(self.network_known_best.unwrap_or(0), self.best_number);
        assert!(self.best_number <= actual_network_best);
        let bar_done_width = u128::from(self.best_number)
            .checked_mul(u128::from(bar_width))
            .unwrap()
            .checked_div(u128::from(actual_network_best))
            .unwrap_or(0);         let bar_done_width = u32::try_from(bar_done_width).unwrap();
        let done_bar1 = "=".repeat(usize::try_from(bar_done_width.saturating_sub(1)).unwrap());
        let done_bar2 = if bar_done_width == bar_width {
            '='
        } else {
            '>'
        };
        let todo_bar = " ".repeat(
            usize::try_from(
                bar_width
                    .checked_sub(bar_done_width.saturating_sub(1).saturating_add(1))
                    .unwrap(),
            )
            .unwrap(),
        );
        assert_eq!(
            done_bar1.len() + 1 + todo_bar.len(),
            usize::try_from(bar_width).unwrap()
        );
        write!(f, "{header}{done_bar1}{done_bar2}{todo_bar}{trailer}")
    }
}
pub struct HashDisplay<'a>(pub &'a [u8]);
impl<'a> fmt::Display for HashDisplay<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x")?;
        if self.0.len() >= 2 {
            let val = u16::from_be_bytes(<[u8; 2]>::try_from(&self.0[..2]).unwrap());
            write!(f, "{val:04x}")?;
        }
        if self.0.len() >= 5 {
            write!(f, "…")?;
        }
        if self.0.len() >= 4 {
            let len = self.0.len();
            let val = u16::from_be_bytes(<[u8; 2]>::try_from(&self.0[len - 2..]).unwrap());
            write!(f, "{val:04x}")?;
        }
        Ok(())
    }
}
pub struct BytesDisplay(pub u64);
impl fmt::Display for BytesDisplay {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut value = self.0 as f64;
        if value < 1000.0 {
            return write!(f, "{value} B");
        }
        value /= 1024.0;
        if value < 100.0 {
            return write!(f, "{value:.1} kiB");
        }
        if value < 1000.0 {
            return write!(f, "{value:.0} kiB");
        }
        value /= 1024.0;
        if value < 100.0 {
            return write!(f, "{value:.1} MiB");
        }
        if value < 1000.0 {
            return write!(f, "{value:.0} MiB");
        }
        value /= 1024.0;
        if value < 100.0 {
            return write!(f, "{value:.1} GiB");
        }
        if value < 1000.0 {
            return write!(f, "{value:.0} GiB");
        }
        value /= 1024.0;
        if value < 100.0 {
            return write!(f, "{value:.1} TiB");
        }
        if value < 1000.0 {
            return write!(f, "{value:.0} TiB");
        }
        value /= 1024.0;
        write!(f, "{value:.1} PiB")
            }
}
struct BlockNumberDisplay(u64);
impl fmt::Display for BlockNumberDisplay {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "#{}", self.0)?;
        Ok(())
    }
}