use indicatif::HumanBytes;

use crate::{
    multibar::MultiBar,
    util::{
        AStrExt, DOWNLOAD_STYLE, EXTRACT_STYLE, INFO_WIDTH, NAME_WIDTH_CUT, NAME_WIDTH_MIN,
        pad_string,
    },
};

pub fn style_bar<'s, const N: usize>(
    prefix: &str,
    name: &str,
    work_per_sec: &str,
    download_done: usize,
    extract_done: usize,
    bar: MultiBar<'s, N>,
    width: u16,
) -> String {
    let name = pad_string(name, (width as usize / NAME_WIDTH_CUT).max(NAME_WIDTH_MIN));
    let status = format!("{} {}", prefix, name);
    let remaining_width =
        width.saturating_sub((name.no_ansi_len() + prefix.no_ansi_len()) as u16 + 6);
    if remaining_width == 0 {
        return status;
    }
    let remaining_width = remaining_width.saturating_sub((INFO_WIDTH as u16 + 3) * 2);

    let possible_chunks = remaining_width.saturating_div(INFO_WIDTH as u16 + 3);
    let possible_chunks = possible_chunks.min(3);
    let leftover_width = ((INFO_WIDTH as u16 + 3) * 2)
        + remaining_width.saturating_sub(possible_chunks * (INFO_WIDTH as u16 + 3));
    let download_done_human = pad_string(
        DOWNLOAD_STYLE
            .style(HumanBytes(download_done as u64).to_string())
            .to_string(),
        INFO_WIDTH,
    );

    let extract_done_human = pad_string(
        EXTRACT_STYLE
            .style(HumanBytes(extract_done as u64).to_string())
            .to_string(),
        INFO_WIDTH,
    );
    let work_per_sec = pad_string(work_per_sec, INFO_WIDTH);
    let bar = bar.scale(leftover_width as u64).to_string();

    match possible_chunks {
        0 => format!("{status} | [{bar}]"),
        1 => format!("{status} | {download_done_human} | [{bar}]"),
        2 => format!("{status} | {work_per_sec} | {download_done_human} | [{bar}]"),
        _ => {
            format!(
                "{status} | {work_per_sec} | {download_done_human} | {extract_done_human} | [{bar}]"
            )
        }
    }
}
