const normalizeHex = (hex) => {
  if (typeof hex !== 'string') {
    return '';
  }
  let cleaned = hex.trim().replace(/^0x/i, '').replace(/\s+/g, '');
  if (cleaned.length % 2 === 1) {
    cleaned = `0${cleaned}`;
  }
  return cleaned;
};

const toHex = (value) => `0x${value.toString(16).padStart(2, '0')}`;

const readUInt16 = (buffer, offset) => buffer.readUInt16BE(offset);

export const parse0x36 = (udpRaw) => {
  const cleaned = normalizeHex(udpRaw);
  const buffer = cleaned ? Buffer.from(cleaned, 'hex') : Buffer.alloc(0);
  const sysLockStatus = buffer.length > 0 ? buffer[0] : null;
  const reportCount = buffer.length > 7 ? buffer[7] : null;
  let offset = 8;
  const devices = [];
  for (let i = 0; i < (reportCount || 0) && offset + 5 < buffer.length; i += 1) {
    devices.push({
      dev_type: buffer[offset],
      dev_addr: buffer[offset + 1],
      dev_loop: readUInt16(buffer, offset + 2),
      dev_data: readUInt16(buffer, offset + 4)
    });
    offset += 6;
  }
  const faultCount = offset < buffer.length ? buffer[offset] : null;
  offset += 1;
  const faults = [];
  for (let i = 0; i < (faultCount || 0) && offset + 5 < buffer.length; i += 1) {
    faults.push({
      fault_dev_type: buffer[offset],
      fault_dev_addr: buffer[offset + 1],
      fault_dev_loop: readUInt16(buffer, offset + 2),
      error_type: buffer[offset + 4],
      error_data: buffer[offset + 5]
    });
    offset += 6;
  }
  return {
    sysLockStatus,
    reportCount,
    faultCount,
    devices,
    faults
  };
};

export const parse0x0fDownlink = (udpRaw) => {
  const cleaned = normalizeHex(udpRaw);
  const buffer = cleaned ? Buffer.from(cleaned, 'hex') : Buffer.alloc(0);
  const controlCount = buffer.length > 0 ? buffer[0] : null;
  let offset = 1;
  const controlParams = [];
  for (let i = 0; i < (controlCount || 0) && offset + 5 < buffer.length; i += 1) {
    const typeValue = readUInt16(buffer, offset + 4);
    controlParams.push({
      dev_type: buffer[offset],
      dev_addr: buffer[offset + 1],
      loop: readUInt16(buffer, offset + 2),
      type: typeValue,
      type_l: buffer[offset + 4],
      type_h: buffer[offset + 5]
    });
    offset += 6;
  }
  return {
    controlCount,
    controlParams
  };
};

export const parse0x0fAck = (udpRaw) => {
  const cleaned = normalizeHex(udpRaw);
  const buffer = cleaned ? Buffer.from(cleaned, 'hex') : Buffer.alloc(0);
  const ackCode = buffer.length > 1 ? toHex(buffer[1]) : null;
  return { ackCode };
};
