"""
Combine global, group, device (and optional zone) brightness into one 0–255 wire value.

Formula: ``(f1/255) * (f2/255) * ... * (fn/255) * 255`` with integer rounding — one ``b`` sent to the driver.
"""

from __future__ import annotations

from models.device import normalize_mac


def clamp255(value) -> int:
    try:
        v = int(value)
    except (TypeError, ValueError):
        return 255
    return max(0, min(255, v))


def multiply_brightness_factors(factors: list) -> int:
    """Product ``(f1/255)*(f2/255)*...*255``; each factor clamped to 0..255."""
    if not factors:
        return 255
    fs = [clamp255(f) for f in factors]
    if len(fs) == 1:
        return fs[0]
    num = 1
    for f in fs:
        num *= f
    den = 255 ** (len(fs) - 1)
    return max(0, min(255, (num + den // 2) // den))


def _mac_in_device_list(raw_list, target_mac: str) -> bool:
    tm = normalize_mac(target_mac)
    if not tm:
        return False
    if not isinstance(raw_list, list):
        return False
    for raw in raw_list:
        if normalize_mac(str(raw)) == tm:
            return True
    return False


def effective_brightness_for_mac(
    settings_obj,
    groups_model,
    devices_model,
    mac: str,
    *,
    zone_brightness=None,
) -> int:
    """
    Factors (each 0..255): Pi **global_brightness**, each group's **output_brightness**
    (neutral 255 if the device is in no group), device **output_brightness** (default 255),
    optional **zone_brightness** from the zone slider when applying live.
    """
    m = normalize_mac(mac)
    if not m:
        return 255

    g_global = clamp255(settings_obj.get("global_brightness", 255))

    dev_doc = devices_model.read(m)
    if dev_doc is not None and dev_doc.get("output_brightness") is not None:
        d_b = clamp255(dev_doc.get("output_brightness"))
    else:
        d_b = 255

    group_factors = []
    for _gid, gdoc in groups_model.items():
        if not isinstance(gdoc, dict):
            continue
        if not _mac_in_device_list(gdoc.get("devices"), m):
            continue
        group_factors.append(clamp255(gdoc.get("output_brightness", 255)))

    if not group_factors:
        group_factors = [255]

    factors = [g_global, *group_factors, d_b]
    if zone_brightness is not None:
        factors.append(clamp255(zone_brightness))

    return multiply_brightness_factors(factors)
