"""Build binary ESP-NOW CMD / GROUP_CMD packets from preset/select data."""

from __future__ import annotations

from typing import Any, Dict, List, Optional

from util.binary_envelope import pack_binary_envelope_v2
from util.espnow_wire import MAX_ESPNOW_PAYLOAD, pack_cmd, pack_group_cmd


def v1_dict_to_cmd_packet(body: Dict[str, Any]) -> bytes:
    save = bool(body.get("save"))
    kw: Dict[str, Any] = {}
    if "presets" in body:
        kw["presets"] = body["presets"]
    if "select" in body:
        kw["select"] = body["select"]
    if "default" in body:
        kw["default"] = body["default"]
        kw["default_targets"] = body.get("targets")
    if "b" in body:
        kw["brightness_0_255"] = int(body["b"])
    return pack_cmd(pack_binary_envelope_v2(**kw), save=save)


def build_preset_cmd_chunks(
    presets_by_name: Dict[str, Any],
    *,
    save: bool = False,
    default: Optional[str] = None,
    max_payload: int = MAX_ESPNOW_PAYLOAD,
) -> List[bytes]:
    """Chunk presets into CMD packets each ≤ max_payload bytes."""
    entries = list(presets_by_name.items())
    chunks: List[bytes] = []
    batch: Dict[str, Any] = {}

    def _packet_for(presets_map: Dict[str, Any], *, final_save: bool, def_id: Optional[str]):
        kw: Dict[str, Any] = {"presets": presets_map}
        if def_id is not None:
            kw["default"] = def_id
        return pack_cmd(pack_binary_envelope_v2(**kw), save=final_save)

    for name, preset_obj in entries:
        trial = dict(batch)
        trial[name] = preset_obj
        try:
            pkt = _packet_for(trial, final_save=False, def_id=None)
        except ValueError:
            pkt = b"\xff\xff"
        if len(pkt) <= max_payload or not batch:
            batch = trial
        else:
            chunks.append(_packet_for(batch, final_save=False, def_id=None))
            batch = {name: preset_obj}

    if batch:
        chunks.append(
            _packet_for(batch, final_save=save, def_id=str(default) if default else None),
        )

    return [c for c in chunks if c and c[0] == 0x4C]
