///|
/// CoE Emergency message decoding per ETG.1000.6 ยง5.6.3.
/// Emergency objects are sent unsolicited by slaves on error conditions.

///|
/// Decoded CoE Emergency message.
pub(all) struct EmergencyMessage {
  /// Emergency error code (2 bytes, ETG.1000.6 Table 44).
  error_code : UInt
  /// Error register value (1 byte, object 0x1001).
  error_register : Byte
  /// Manufacturer-specific error data (5 bytes).
  data : Bytes
} derive(Eq, Debug)

///|
/// CoE Emergency message payload size (error_code + error_register + data).
let emergency_payload_len : Int = 8

///|
/// Decode a CoE Emergency message from the CoE payload
/// (after mailbox header + CoE header, i.e., the SDO/Emergency data area).
pub fn decode_emergency(payload : Bytes) -> EmergencyMessage raise @hal.EcError {
  if payload.length() < emergency_payload_len {
    raise @hal.EcError::MailboxProtocol(
      "emergency payload too short: " + payload.length().to_string(),
    )
  }
  let error_code = payload[0].to_uint() | (payload[1].to_uint() << 8)
  let error_register = payload[2]
  let data = Bytes::makei(5, fn(i) { payload[3 + i] })
  { error_code, error_register, data }
}

///|
/// Decode a full mailbox frame as a CoE Emergency message.
/// Parses mailbox header, verifies CoE type and Emergency service,
/// then decodes the emergency payload.
pub fn decode_emergency_frame(
  frame : Bytes,
) -> (MailboxHeader, EmergencyMessage) raise @hal.EcError {
  let mbh = MailboxHeader::from_bytes(frame)
  if mbh.mb_type != CoE {
    raise @hal.EcError::MailboxProtocol(
      "expected CoE mailbox for emergency, got " + @debug.to_string(mbh.mb_type),
    )
  }
  // Verify we have enough data for CoE header + Emergency payload
  // Mailbox header = 6 bytes, CoE header = 2 bytes, Emergency = 8 bytes
  if frame.length() < 16 {
    raise @hal.EcError::MailboxProtocol(
      "emergency frame too short: " + frame.length().to_string(),
    )
  }
  // CoE header: service type in bits [15:12]
  let coe_word = frame[6].to_uint() | (frame[7].to_uint() << 8)
  let svc_field = (coe_word >> 12) & 0xFU
  if svc_field != 1U {
    // 1 = Emergency
    raise @hal.EcError::MailboxProtocol(
      "expected Emergency service (1), got " +
      svc_field.reinterpret_as_int().to_string(),
    )
  }
  // Emergency payload starts at offset 8 (after mailbox header + CoE header)
  let payload = Bytes::makei(emergency_payload_len, fn(i) { frame[8 + i] })
  let emg = decode_emergency(payload)
  (mbh, emg)
}