"""Zengge / iLightsIn BLE controller protocol.

Zengge (a.k.a. iLightsIn, Mohuan Lighting, generic "LED BLE") controllers
use a distinct wire protocol from Triones despite targeting the same
segment. Colors are framed with a leading ``0x56`` and trailed with
``0xAA``:

    ``56 RR GG BB 00 F0 AA``  — set RGB (bright=0xF0 marker)
    ``56 00 00 00 WW 0F AA``  — set warm-white (when RGBW is wired)

Power is a separate 7-byte frame:

    ``CC 23 33``  — ON
    ``CC 24 33``  — OFF

References:
    * https://github.com/mjg59/python-zengge
    * https://github.com/madhead/saberlight
"""

from __future__ import annotations

from ledgrab.core.devices.ble_protocols import BLEProtocol

# Zengge controllers share the FFE0/FFE1 pair with SP110E but run a different
# command protocol — a recurring source of confusion. Differentiate them by
# advertisement name (see ``name_prefixes``) or by user-picked family.
_SERVICE_UUID = "0000ffe0-0000-1000-8000-00805f9b34fb"
_WRITE_CHAR_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"


def _clamp_byte(value: int) -> int:
    if value < 0:
        return 0
    if value > 255:
        return 255
    return value


def encode_color(r: int, g: int, b: int, brightness: int = 255) -> bytes:
    """Build a Zengge "set RGB" frame."""
    r = _clamp_byte(r)
    g = _clamp_byte(g)
    b = _clamp_byte(b)
    brightness = _clamp_byte(brightness)
    if brightness != 255:
        r = (r * brightness) // 255
        g = (g * brightness) // 255
        b = (b * brightness) // 255
    return bytes((0x56, r, g, b, 0x00, 0xF0, 0xAA))


def encode_power(on: bool) -> bytes:
    """Build a Zengge power on/off frame."""
    return bytes((0xCC, 0x23 if on else 0x24, 0x33))


PROTOCOL = BLEProtocol(
    family="zengge",
    display_name="Zengge / iLightsIn",
    service_uuid=_SERVICE_UUID,
    write_char_uuid=_WRITE_CHAR_UUID,
    write_with_response=False,
    encode_color=encode_color,
    encode_power=encode_power,
    name_prefixes=("Zengge", "iLightsIn", "Mohuan"),
)
