// Each button maps to (room, light) via global roomConfig.switchBindings. See /root/.node-red/room-config.js.
// Supports single-device payload (action, friendly_name at top level) and multi-device payload (keyed by IEEE address).
const actionToSwitch = { single: 1, double: 2, hold: 3, release: 4, triple: 5, quad: 6 };
const config = global.get('roomConfig');
const switchBindings = (config && config.switchBindings) ? config.switchBindings : {};
const deviceToRoom = (config && config.deviceToRoom) ? config.deviceToRoom : { 'Office Switch': 'cmd_livingroom' };
// Optional: map IEEE address to friendly name when multi-device node doesn't provide it. e.g. deviceIdToName: { '0xa4c138a5b9771b05': 'Office Switch' }
const deviceIdToName = (config && config.deviceIdToName) ? config.deviceIdToName : {};

const payload = msg.payload != null ? msg.payload : {};
// Payload can be: single-device { action, friendly_name }, multi-device { "0x...": { ... } }, or plain action string "1_single"
let friendlyName = (typeof payload === 'object' && payload.friendly_name != null) ? payload.friendly_name.toString() : '';
let actionRaw = (typeof payload === 'string' ? payload : (payload.action || payload.click || msg.action || (payload && payload.action)) || '').toString().toLowerCase();

// Multi-device payload: prefer the device that has an action AND a configured binding (so we don't pick another device's stale action)
if (!actionRaw && typeof payload === 'object' && !Array.isArray(payload)) {
  const keys = Object.keys(payload);
  let fallback = null;
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const v = payload[key];
    if (key && key.toLowerCase().indexOf('0x') === 0 && v && typeof v === 'object') {
      const inner = v.payload || v.message || v.state || v;
      const a = (inner.action || inner.click || v.action || v.click || '').toString().toLowerCase();
      if (!a) continue;
      const name = (v.friendly_name || v.name || (v.item && (v.item.friendly_name || v.item.name)) || deviceIdToName[key] || key).toString();
      if (switchBindings[name] || deviceToRoom[name]) {
        actionRaw = a;
        friendlyName = name;
        break;
      }
      if (!fallback) fallback = { actionRaw: a, friendlyName: name };
    }
  }
  if (!actionRaw && fallback) {
    actionRaw = fallback.actionRaw;
    friendlyName = fallback.friendlyName;
  }
}
// If still no action, try msg.data or msg.topic (some nodes put action in topic, e.g. "1_single")
if (!actionRaw && msg.data && msg.data.action) actionRaw = msg.data.action.toString().toLowerCase();
if (!actionRaw && typeof msg.topic === 'string' && /^\d_[a-z_]+$/.test(msg.topic.trim())) actionRaw = msg.topic.trim().toLowerCase();
// If payload was the action string, get friendly_name from topic e.g. zigbee2mqtt/Office Switch/action
if (actionRaw && !friendlyName && typeof msg.topic === 'string') {
  const parts = msg.topic.split('/');
  if (parts.length >= 2) friendlyName = parts[1].trim();  // zigbee2mqtt/Office Switch/action → Office Switch
}

if (!actionRaw) {
  node.warn('[Zigbee to NVL] no action in payload. Keys: ' + (typeof payload === 'object' ? Object.keys(payload).join(', ') : 'n/a'));
  return null;
}

const parts = actionRaw.split('_');
let buttonIndex = null;
if (parts.length >= 2) {
  const n = parseInt(parts[0], 10);
  if (n >= 1 && n <= 6) buttonIndex = n;
}
if (buttonIndex == null) buttonIndex = actionToSwitch[actionRaw];
if (buttonIndex == null && parts.length >= 2) buttonIndex = actionToSwitch[parts.slice(1).join('_')];
if (buttonIndex == null) buttonIndex = actionToSwitch[parts[parts.length - 1]];

if (buttonIndex == null) {
  node.warn('[Zigbee to NVL] unknown action: ' + JSON.stringify(actionRaw));
  return null;
}

node.warn('[Zigbee to NVL] action=' + actionRaw + ' buttonIndex=' + buttonIndex + ' device=' + friendlyName);

// Prefer switchBindings by friendly name; fallback by device ID (IEEE) if we have switchBindingsByDeviceId
const bindingByDeviceId = (config && config.switchBindingsByDeviceId) ? config.switchBindingsByDeviceId : null;
let targets = [];
let binding = switchBindings[friendlyName] && switchBindings[friendlyName][buttonIndex];
if ((binding === undefined || binding === null) && bindingByDeviceId) {
  const deviceId = typeof payload === 'object' && Object.keys(payload).some(function (k) { return k.indexOf('0x') === 0; })
    ? Object.keys(payload).find(function (k) { return k.indexOf('0x') === 0; })
    : null;
  if (deviceId) binding = bindingByDeviceId[deviceId] && bindingByDeviceId[deviceId][buttonIndex];
}
if (binding !== undefined && binding !== null) {
  targets = Array.isArray(binding) ? binding : [binding];
  targets = targets.filter(function (t) { return t && t.room && t.light >= 1 && t.light <= 6; });
}
if (targets.length === 0) {
  const room = deviceToRoom[friendlyName] || 'cmd_livingroom';
  targets = [{ room: room, light: buttonIndex }];
  node.warn('[Zigbee to NVL] no switchBindings for ' + friendlyName + ' btn' + buttonIndex + ', using fallback: ' + room + ' light ' + buttonIndex);
}

if (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });
const state = flow.get('nvlInState');
const clearList = [];

for (const t of targets) {
  const key = 'zigbee_sw' + t.light;
  if (!state.rooms[t.room]) state.rooms[t.room] = {};
  state.rooms[t.room][key] = true;
  clearList.push({ room: t.room, key: key });
}

flow.set('nvlInState', state);

node.warn('[Zigbee to NVL] ' + (friendlyName || 'device') + ' btn' + buttonIndex + ' → ' + targets.map(function (t) { return t.room + ' L' + t.light; }).join(', '));

msg.payload = { buildAndSend: true };
msg.zigbeeClear = clearList;
return msg;
