# coding: utf-8
"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2

The functions declared in this module should cover the different
usecases needed to generate a string representation of a file size
using several different units. Since there are many standards regarding
file size units, three different functions have been implemented.

See Also:
    * `Wikipedia: Binary prefix <https://en.wikipedia.org/wiki/Binary_prefix>`_

"""


from typing import Iterable, List, Optional, Tuple

from rich.text import Text


def _to_str(
    size: int,
    suffixes: Iterable[str],
    base: int,
    *,
    precision: Optional[int] = 1,
    separator: Optional[str] = " ",
) -> str:
    if size == 1:
        return "1 byte"

    if size < base:
        return f"{size:,} bytes"

    suffix: str
    for i, suffix in enumerate(suffixes, 2):  # noqa: B007
        unit = base**i
        if size < unit:
            break
    return f"{(base * size / unit):,.{precision}f}{separator}{suffix}"


def pick_unit_and_suffix(size: int, suffixes: List[str], base: int) -> Tuple[int, str]:
    """Pick a suffix and base for the given size."""

    suffix: str
    for i, suffix in enumerate(suffixes):
        unit = base**i
        if size < unit * base:
            break
    return unit, suffix


def decimal(
    size: int,
    *,
    precision: Optional[int] = 1,
    separator: Optional[str] = " ",
) -> str:
    """Convert a filesize in to a string (powers of 1000, SI prefixes).

    In this convention, ``1000 B = 1 kB``.

    This is typically the format used to advertise the storage
    capacity of USB flash drives and the like (*256 MB* meaning
    actually a storage capacity of more than *256 000 000 B*),
    or used by **Mac OS X** since v10.6 to report file sizes.

    Arguments:
        int (size): A file size.
        int (precision): The number of decimal places to include (default = 1).
        str (separator): The string to separate the value from the units (default = " ").

    Returns:
        `str`: A string containing a abbreviated file size and units.

    Example:
        >>> filesize.decimal(30000)
        '30.0 kB'
        >>> filesize.decimal(30000, precision=2, separator="")
        '30.00kB'

    """
    return _to_str(
        size,
        ("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"),
        1000,
        precision=precision,
        separator=separator,
    )


def render_file_unit(completed: int, config: dict, total: Optional[int] = None) -> Text:
    """
    Calculate common unit for completed and total.
    Borrowed from https://github.com/Textualize/rich
    """

    if completed < 0:
        return Text("N/A", style="bright_black")

    unit_and_suffix_calculation_base = (
        int(total) if total is not None else completed
    )
    unit, suffix = pick_unit_and_suffix(
        unit_and_suffix_calculation_base,
        ["bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"],
        1024,
    )

    precision = 0 if unit == 1 else 1

    completed_ratio = completed / unit
    completed_str = f"{completed_ratio:,.{precision}f}"

    if total is not None:
        total = int(total)
        total_ratio = total / unit
        total_str = f"{total_ratio:,.{precision}f}"

        style = get_style(completed / total * 100., config)
        completed_txt = Text(f"{completed_str}", style=style)
        return completed_txt + Text(f"/{total_str} {suffix}", style=config["suffix_style"])

    return (Text(f"{completed_str}", style=config["val_normal_style"]) +
            Text(f" {suffix}", style=config["suffix_style"]))


def render_energy_unit(energy: float, config: dict) -> Text:
    """
    Calculate common unit for completed and total.
    Borrowed from https://github.com/Textualize/rich
    """

    unit, suffix = pick_unit_and_suffix(
        int(energy),
        ["J", "kJ", "MJ", "GJ", "TJ", "PJ", "EJ", "ZJ", "YJ"],
        1000,
    )

    precision = 0 if unit == 1 else 1

    energy_ratio = energy / unit
    energy_str = f"{energy_ratio:,.{precision}f}"

    return (Text(f"{energy_str}", style=config["val_normal_style"])
            + Text(f" {suffix}", style=config["suffix_style"]))


def get_style(percent: float, config: dict) -> str:
    """Get style by percent"""

    style = config["val_normal_style"]
    if 50.0 < percent <= 80.0:
        style = config["val_warn_style"]
    elif percent > 80.0:
        style = config["val_error_style"]

    return style
