"""Formats raw robot counter values into display-ready strings for the OperatorHMI.

The web frontend treats the strings produced here as opaque — all unit,
precision, and label decisions live in this module.
"""

PLACEHOLDER = "--"


def format_int(value):
    if value is None:
        return PLACEHOLDER
    return str(int(value))


def format_parts(count, total):
    if count is None:
        return PLACEHOLDER
    if not total:
        return "0 (0.00%)"
    pct = (count / total) * 100
    return "{} ({:.2f}%)".format(int(count), pct)


def format_duration(seconds):
    if seconds is None:
        return PLACEHOLDER
    seconds = int(seconds)
    if seconds < 60:
        return "{} s".format(seconds)
    minutes, sec = divmod(seconds, 60)
    return "{} min {} s".format(minutes, sec)


def format_minutes(minutes):
    if minutes is None:
        return PLACEHOLDER
    minutes = int(minutes)
    if minutes < 60:
        return "{} min".format(minutes)
    hours, mins = divmod(minutes, 60)
    return "{} h {} min".format(hours, mins)


def format_int_array(values):
    if not values:
        return []
    return [str(int(v)) for v in values]


def build_info_variables(raw):
    """Build the display-ready `variables` dict consumed by info.js.

    `raw` is a dict of raw numbers/lists matching the backend interface:
        uptime_complete, uptime_last, uptime_enabled, uptime_motion  (minutes)
        program_starts_total, program_starts_last                    (int)
        program_duration_last                                        (seconds)
        parts_good, parts_bad                                        (int)
        robot_axis_direction_changes, external_axis_direction_changes (int[])

    Missing keys become PLACEHOLDER strings (or empty arrays).
    """
    parts_good = raw.get("parts_good")
    parts_bad = raw.get("parts_bad")
    parts_total = (parts_good or 0) + (parts_bad or 0)

    return {
        "programStartsTotal":  format_int(raw.get("program_starts_total")),
        "programStarts":       format_int(raw.get("program_starts_last")),
        "lastProgramDuration": format_duration(raw.get("program_duration_last")),
        "partsGood":           format_parts(parts_good, parts_total),
        "partsBad":            format_parts(parts_bad, parts_total),
        "operatingTime":        format_minutes(raw.get("uptime_last")),
        "operatingTimeTotal":   format_minutes(raw.get("uptime_complete")),
        "operatingTimeEnabled": format_minutes(raw.get("uptime_enabled")),
        "operatingTimeMotion":  format_minutes(raw.get("uptime_motion")),
        "robotAxisDirectionChanges":    format_int_array(raw.get("robot_axis_direction_changes")),
        "externalAxisDirectionChanges": format_int_array(raw.get("external_axis_direction_changes")),
    }
