from tqdm import tqdm

GREY  = "\033[90m"
GREEN = "\033[92m"
RESET = "\033[0m"


def loading_bars():
    bar_format_normal        = "{bar} {l_bar} {remaining} {postfix}"
    bar_format_learner       = "{bar} {remaining} {postfix}"
    bar_format_learner_batch = "{bar} {remaining} {postfix}"
    return bar_format_normal, bar_format_learner, bar_format_learner_batch


def get_loading_bar_style():
    return (f"{GREY}━{RESET}", f"{GREEN}━{RESET}")


def initialize_loading_bar(total, desc, ncols, bar_format,
                           loading_bar_style=get_loading_bar_style(),
                           leave=True, dynamic_ncols=False):
    return tqdm(
        total=total,
        leave=leave,
        desc=desc,
        ascii=loading_bar_style,
        bar_format=bar_format,
        ncols=ncols,
        dynamic_ncols=dynamic_ncols,
    )


def initialize_loading_bar_batch(total, desc, ncols,
                                 loading_bar_style=get_loading_bar_style(),
                                 leave=True, dynamic_ncols=False):
    _, _, bar_format_learner_batch = loading_bars()
    return tqdm(
        total=total,
        leave=leave,
        desc=desc,
        ascii=loading_bar_style,
        bar_format=bar_format_learner_batch,
        ncols=ncols,
        dynamic_ncols=dynamic_ncols,
    )


# ─────────────────────────────────────────────────────────────────────────────
#  SABİT GENİŞLİKLİ FORMAT FONKSİYONLARI
#  Sayı ne kadar büyürse büyüsün, her alan aynı karakter sayısında kalır.
#  Böylece postfix toplam genişliği değişmez → bar titremez, kaymaz.
# ─────────────────────────────────────────────────────────────────────────────

_FW_NUM  = 11   # loss / accuracy için alan genişliği  → "-1.2346e+09" = 11 kar.
_FW_FRAC = 11   # "X/Y" değerleri için alan genişliği  → "1000/1000"   =  9 kar.


def format_number(val: float) -> str:
    """
    Sabit _FW_NUM karakterlik sayısal format.

    Örnekler (her biri 11 karakter, sağa hizalı):
        '     0.9123'   (normal float)
        '     0.0001'
        ' 1.2346e+04'   (büyük sayı)
        '-3.1416e-05'   (küçük negatif)
        '        NaN'
    """
    if val != val:
        return f"{'NaN':>{_FW_NUM}}"
    if abs(val) >= 1e4 or (val != 0 and abs(val) < 1e-2):
        s = f"{val:.4e}"
    else:
        s = f"{val:.4f}"
    return f"{s:>{_FW_NUM}}"


def format_fraction(current: int, total: int) -> str:
    """
    Sabit _FW_FRAC karakterlik 'current/total' formatı.
    total'in karakter genişliğine göre current'i pad'ler.

    Örnek (total=1000, _FW_FRAC=11):
        format_fraction(1,    1000) → '     1/1000'
        format_fraction(999,  1000) → '   999/1000'
        format_fraction(1000, 1000) → '  1000/1000'
    """
    w = len(str(total))
    s = f"{current:{w}d}/{total}"
    return f"{s:>{_FW_FRAC}}"