"""End-to-end hardware test on the MUM (Melexis Universal Master).

Power the ECU via MUM's built-in power output, then activate the RGB LED via
the master-published ALM_Req_A frame (ID 0x0A) and verify the slave responds
on ALM_Status (ID 0x11).

Frame layout (from vendor/4SEVEN_color_lib_test.ldf, ALM_Req_A @ 0x0A, 8B):
  byte 0  AmbLightColourRed   (0..255)
  byte 1  AmbLightColourGreen (0..255)
  byte 2  AmbLightColourBlue  (0..255)
  byte 3  AmbLightIntensity   (0..255)
  byte 4  AmbLightUpdate (bits 0-1) | AmbLightMode (bits 2-7)
  byte 5  AmbLightDuration
  byte 6  AmbLightLIDFrom
  byte 7  AmbLightLIDTo

The ECU answers ALM_Req_A only when AmbLightLIDFrom <= ALMNadNo <= LIDTo, so
we read the current NAD from ALM_Status first and target that NAD exactly.
"""
from __future__ import annotations

import pytest

from ecu_framework.config import EcuTestConfig
from ecu_framework.lin.base import LinFrame, LinInterface


pytestmark = [pytest.mark.hardware, pytest.mark.mum]

ALM_REQ_A_ID = 0x0A
ALM_STATUS_ID = 0x11

DEFAULT_RGB = (0xFF, 0xFF, 0xFF)
DEFAULT_INTENSITY = 0xFF


def _build_alm_req_a_payload(
    r: int, g: int, b: int,
    intensity: int = DEFAULT_INTENSITY,
    update: int = 0,
    mode: int = 0,
    duration: int = 0,
    lid_from: int = 0x01,
    lid_to: int = 0xFF,
) -> bytes:
    """Pack RGB+mode signals into the 8-byte ALM_Req_A payload."""
    byte4 = (update & 0x03) | ((mode & 0x3F) << 2)
    return bytes([
        r & 0xFF, g & 0xFF, b & 0xFF,
        intensity & 0xFF,
        byte4 & 0xFF,
        duration & 0xFF,
        lid_from & 0xFF,
        lid_to & 0xFF,
    ])


def test_mum_e2e_power_on_then_led_activate(config: EcuTestConfig, lin: LinInterface, rp):
    """
    Title: MUM E2E - Power ECU, Read NAD, Activate RGB LED

    Description:
        Drives the full hardware path through the Melexis Universal Master:
        the `lin` fixture has already powered the ECU via power_out0 and set
        up the LIN bus. This test reads ALM_Status to discover the slave's
        NAD, publishes ALM_Req_A targeting that NAD with full white at full
        intensity, and re-reads ALM_Status to confirm the bus is alive.

    Requirements: REQ-MUM-LED-ACTIVATE

    Test Steps:
        1. Skip unless interface.type == 'mum'
        2. Read ALM_Status (0x11) and extract ALMNadNo (byte 0 lower 8 bits)
        3. Build ALM_Req_A payload with RGB=(0xFF,0xFF,0xFF), intensity=0xFF,
           targeting LIDFrom=LIDTo=current_nad
        4. Publish ALM_Req_A via lin.send()
        5. Re-read ALM_Status and assert it still returns a valid frame

    Expected Result:
        - First ALM_Status read returns a 4-byte frame with a NAD in 0x01..0xFE
        - Second ALM_Status read returns a frame (bus still alive after Tx)
    """
    if config.interface.type != "mum":
        pytest.skip("interface.type must be 'mum' for this test")

    # Step 2: read current NAD from ALM_Status
    status = lin.receive(id=ALM_STATUS_ID, timeout=1.0)
    assert status is not None, "No ALM_Status received — check MUM/ECU wiring and power"
    assert len(status.data) >= 1, f"ALM_Status too short: {status.data!r}"
    current_nad = status.data[0]
    rp("alm_status_data_hex", bytes(status.data).hex())
    rp("current_nad", f"0x{current_nad:02X}")
    assert 0x01 <= current_nad <= 0xFE, (
        f"ALMNadNo {current_nad:#x} is out of valid range; ECU may be unconfigured"
    )

    # Step 3 + 4: target the discovered NAD with full white
    payload = _build_alm_req_a_payload(
        *DEFAULT_RGB,
        intensity=DEFAULT_INTENSITY,
        lid_from=current_nad,
        lid_to=current_nad,
    )
    rp("tx_id", f"0x{ALM_REQ_A_ID:02X}")
    rp("tx_data_hex", payload.hex())
    rp("rgb", list(DEFAULT_RGB))
    rp("intensity", DEFAULT_INTENSITY)

    lin.send(LinFrame(id=ALM_REQ_A_ID, data=payload))

    # Step 5: confirm bus liveness after the activation frame
    status_after = lin.receive(id=ALM_STATUS_ID, timeout=1.0)
    rp("post_status_present", status_after is not None)
    if status_after is not None:
        rp("post_status_data_hex", bytes(status_after.data).hex())
    assert status_after is not None, (
        "ALM_Status not received after publishing ALM_Req_A — ECU may have reset"
    )
