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

Powers the ECU via MUM's built-in power output, reads ALM_Status to discover
the slave's NAD, then activates the RGB LED via the master-published
ALM_Req_A frame targeting that NAD with full white at full intensity. Frame
layouts are taken from the LDF at runtime via the `ldf` fixture, so signal
names and bit positions stay in sync with `vendor/4SEVEN_color_lib_test.ldf`
without manual byte building.
"""
from __future__ import annotations

import pytest

from ecu_framework.lin.base import LinFrame, LinInterface


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


def test_mum_e2e_power_on_then_led_activate(lin: LinInterface, ldf, 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.
        Frame layouts come from the LDF database, not hand-coded byte
        positions.

    Requirements: REQ-MUM-LED-ACTIVATE

    Test Steps:
        1. Skip unless interface.type == 'mum'
        2. Read ALM_Status; decode signals via the LDF; extract ALMNadNo
        3. Build the ALM_Req_A payload via ldf.frame("ALM_Req_A").pack(...),
           targeting LIDFrom=LIDTo=current_nad with full-white RGB
        4. Publish ALM_Req_A via lin.send()
        5. Re-read ALM_Status and confirm the bus still returns a valid frame

    Expected Result:
        - First ALM_Status decode yields ALMNadNo in 0x01..0xFE
        - lin.send() of the LDF-packed frame succeeds
        - Second ALM_Status read returns a frame (bus still alive after Tx)
    """
    # MUM gate is enforced by tests/hardware/mum/conftest.py::_require_mum
    req_a = ldf.frame("ALM_Req_A")
    status = ldf.frame("ALM_Status")
    rp("ldf_path", str(ldf.path))
    rp("req_a_id", f"0x{req_a.id:02X}")
    rp("status_id", f"0x{status.id:02X}")

    # Step 2: read ALM_Status and decode it via the LDF.
    rx = lin.receive(id=status.id, timeout=1.0)
    assert rx is not None, "No ALM_Status received — check MUM/ECU wiring and power"
    decoded = status.unpack(bytes(rx.data))
    current_nad = int(decoded["ALMNadNo"])
    rp("alm_status_decoded", decoded)
    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 at full intensity.
    payload = req_a.pack(
        AmbLightColourRed=0xFF,
        AmbLightColourGreen=0xFF,
        AmbLightColourBlue=0xFF,
        AmbLightIntensity=0xFF,
        AmbLightUpdate=0,        # 0 = Immediate color update
        AmbLightMode=0,          # 0 = Immediate Setpoint
        AmbLightDuration=0,
        AmbLightLIDFrom=current_nad,
        AmbLightLIDTo=current_nad,
    )
    rp("tx_data_hex", payload.hex())
    lin.send(LinFrame(id=req_a.id, data=payload))

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