import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IIntegrationEvent, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
import type {
  IDevoloActionDescriptor,
  IDevoloCommand,
  IDevoloConfig,
  IDevoloDeviceInfo,
  IDevoloEvent,
  IDevoloFirmwareUpdate,
  IDevoloGuestWifiState,
  IDevoloManualEntry,
  IDevoloNeighborWifiNetwork,
  IDevoloPlcDevice,
  IDevoloPlcLink,
  IDevoloSensorMap,
  IDevoloSnapshot,
  IDevoloSwitchMap,
  IDevoloSwitchState,
  IDevoloWifiStation,
  TDevoloActionName,
  TDevoloCommandType,
  TDevoloFeature,
} from './devolo_home_network.types.js';
import { devoloHomeNetworkDefaultPort, devoloHomeNetworkDomain } from './devolo_home_network.types.js';

const manufacturer = 'devolo';

const actionLabels: Record<TDevoloActionName, string> = {
  identify: 'Identify device with a blinking LED',
  pairing: 'Start PLC pairing',
  restart: 'Restart device',
  start_wps: 'Start WPS',
  set_leds: 'Enable LEDs',
  set_guest_wifi: 'Enable guest Wi-Fi',
  install_firmware: 'Regular firmware',
};

const actionTypes: Record<TDevoloActionName, TDevoloCommandType> = {
  identify: 'plc.identify',
  pairing: 'plc.pair_device',
  restart: 'device.restart',
  start_wps: 'wifi.start_wps',
  set_leds: 'device.set_leds',
  set_guest_wifi: 'wifi.set_guest_access',
  install_firmware: 'firmware.install',
};

export class DevoloHomeNetworkMapper {
  public static toSnapshot(configArg: IDevoloConfig, connectedArg?: boolean, eventsArg: IDevoloEvent[] = []): IDevoloSnapshot {
    const source = configArg.snapshot;
    const manualSnapshots = (configArg.manualEntries || [])
      .map((entryArg) => entryArg.snapshot)
      .filter((snapshotArg): snapshotArg is IDevoloSnapshot => Boolean(snapshotArg));
    const manualData = this.mergeManualEntries(configArg.manualEntries || []);
    const snapshotSources = [source, ...manualSnapshots].filter((snapshotArg): snapshotArg is IDevoloSnapshot => Boolean(snapshotArg));
    const plcDevices = this.uniquePlcDevices([
      ...snapshotSources.flatMap((snapshotArg) => snapshotArg.plcDevices || []),
      ...(configArg.plcDevices || []),
      ...(configArg.devices || []),
      ...manualData.plcDevices,
    ]);
    const plcLinks = this.uniquePlcLinks([
      ...snapshotSources.flatMap((snapshotArg) => snapshotArg.plcLinks || []),
      ...(configArg.plcLinks || []),
      ...(configArg.links || []),
      ...(configArg.dataRates || []),
      ...manualData.plcLinks,
    ]);
    const wifiStations = this.uniqueWifiStations([
      ...snapshotSources.flatMap((snapshotArg) => snapshotArg.wifiStations || []),
      ...(configArg.wifiStations || []),
      ...(configArg.stations || []),
      ...(configArg.clients || []),
      ...manualData.wifiStations,
    ]);
    const neighboringWifiNetworks = this.uniqueNeighborNetworks([
      ...snapshotSources.flatMap((snapshotArg) => snapshotArg.neighboringWifiNetworks || []),
      ...(configArg.neighboringWifiNetworks || []),
      ...(configArg.neighbors || []),
      ...manualData.neighboringWifiNetworks,
    ]);
    const device = this.deviceInfo(configArg, snapshotSources, manualData.device, plcDevices, plcLinks, wifiStations, neighboringWifiNetworks);
    const switches = this.switches([
      ...snapshotSources.map((snapshotArg) => snapshotArg.switches),
      manualData.switches,
      configArg.switches,
    ]);
    const firmware = this.firmware([
      ...snapshotSources.map((snapshotArg) => snapshotArg.firmware),
      manualData.firmware,
      configArg.firmware,
      this.firmwareFromDevice(device),
    ]);
    const sensors = this.sensorMap([
      ...snapshotSources.map((snapshotArg) => snapshotArg.sensors),
      manualData.sensors,
      configArg.sensors,
    ], device, plcDevices, plcLinks, wifiStations, neighboringWifiNetworks);
    const actions = this.uniqueActions([
      ...snapshotSources.flatMap((snapshotArg) => snapshotArg.actions || []),
      ...manualData.actions,
      ...(configArg.actions || []),
      ...this.actionsFromSnapshot(device, plcDevices, plcLinks, wifiStations, switches, firmware),
    ]);
    const hasSnapshotData = Boolean(source || manualSnapshots.length || manualData.hasData || configArg.device || configArg.plcDevices?.length || configArg.devices?.length || configArg.plcLinks?.length || configArg.links?.length || configArg.dataRates?.length || configArg.wifiStations?.length || configArg.stations?.length || configArg.clients?.length || configArg.neighboringWifiNetworks?.length || configArg.neighbors?.length || configArg.firmware || configArg.sensors || configArg.switches);

    return {
      connected: connectedArg ?? configArg.connected ?? source?.connected ?? (hasSnapshotData && source?.connected !== false),
      source: source?.source || (hasSnapshotData ? 'manual' : 'runtime'),
      updatedAt: source?.updatedAt || new Date().toISOString(),
      device,
      plcDevices,
      plcLinks,
      wifiStations,
      neighboringWifiNetworks,
      firmware,
      sensors,
      switches,
      actions,
      events: [...snapshotSources.flatMap((snapshotArg) => snapshotArg.events || []), ...(configArg.events || []), ...eventsArg],
      error: source?.error,
      metadata: this.cleanAttributes({
        ...snapshotSources.reduce((accArg, snapshotArg) => ({ ...accArg, ...snapshotArg.metadata }), {}),
        ...configArg.metadata,
        liveHttpImplemented: false,
        commandExecutorConfigured: Boolean(configArg.commandExecutor || configArg.nativeClient?.executeCommand),
      }),
    };
  }

  public static toDevices(snapshotArg: IDevoloSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const devices: plugins.shxInterfaces.data.IDeviceDefinition[] = [this.mainDevice(snapshotArg, updatedAt)];
    for (const device of snapshotArg.plcDevices) {
      if (!this.isLocalPlcDevice(snapshotArg, device)) {
        devices.push(this.plcPeerDevice(snapshotArg, device, updatedAt));
      }
    }
    for (const station of snapshotArg.wifiStations) {
      devices.push(this.stationDevice(snapshotArg, station, updatedAt));
    }
    return this.uniqueDeviceDefinitions(devices);
  }

  public static toEntities(snapshotArg: IDevoloSnapshot): IIntegrationEntity[] {
    const entities: IIntegrationEntity[] = [];
    const usedIds = new Map<string, number>();
    const deviceId = this.mainDeviceId(snapshotArg);
    const deviceName = this.deviceName(snapshotArg.device);
    entities.push(this.entity('binary_sensor', `${deviceName} Connected`, deviceId, `${this.uniqueBase(snapshotArg)}_connected`, snapshotArg.connected ? 'on' : 'off', usedIds, {
      deviceClass: 'connectivity',
      host: snapshotArg.device.host || snapshotArg.device.ipAddress,
      port: snapshotArg.device.port || devoloHomeNetworkDefaultPort,
    }, true));

    const connectedToRouter = this.connectedToRouter(snapshotArg);
    if (connectedToRouter !== undefined) {
      entities.push(this.entity('binary_sensor', `${deviceName} Connected to router`, deviceId, `${this.uniqueBase(snapshotArg)}_connected_to_router`, connectedToRouter ? 'on' : 'off', usedIds, {
        nativeKey: 'connected_to_router',
        deviceClass: 'plug',
        entityCategory: 'diagnostic',
      }, snapshotArg.connected));
    }

    this.pushCoreSensors(entities, snapshotArg, usedIds);
    this.pushSwitchEntities(entities, snapshotArg, usedIds);
    this.pushButtonEntities(entities, snapshotArg, usedIds);
    this.pushFirmwareEntity(entities, snapshotArg, usedIds);
    this.pushPlcLinkEntities(entities, snapshotArg, usedIds);
    this.pushStationEntities(entities, snapshotArg, usedIds);

    return entities;
  }

  public static commandForService(snapshotArg: IDevoloSnapshot, requestArg: IServiceCallRequest): IDevoloCommand | undefined {
    const targetEntity = this.findTargetEntity(snapshotArg, requestArg);

    if (requestArg.domain === devoloHomeNetworkDomain) {
      const action = this.actionFromDomainService(requestArg.service);
      if (!action) {
        return undefined;
      }
      const enabled = action === 'set_leds' || action === 'set_guest_wifi'
        ? this.booleanValue(requestArg.data?.enabled ?? requestArg.data?.state)
        : undefined;
      if ((action === 'set_leds' || action === 'set_guest_wifi') && enabled === undefined) {
        return undefined;
      }
      return this.command(snapshotArg, requestArg, action, targetEntity, enabled, requestArg.data || {});
    }

    if (requestArg.domain === 'button' && requestArg.service === 'press') {
      const action = this.actionValue(targetEntity?.attributes?.nativeAction);
      return action ? this.command(snapshotArg, requestArg, action, targetEntity) : undefined;
    }

    if (requestArg.domain === 'switch' && (requestArg.service === 'turn_on' || requestArg.service === 'turn_off')) {
      const action = this.actionValue(targetEntity?.attributes?.nativeAction);
      if (action !== 'set_leds' && action !== 'set_guest_wifi') {
        return undefined;
      }
      return this.command(snapshotArg, requestArg, action, targetEntity, requestArg.service === 'turn_on');
    }

    if (requestArg.domain === 'update' && (requestArg.service === 'install' || requestArg.service === 'update')) {
      const action = this.actionValue(targetEntity?.attributes?.nativeAction) || 'install_firmware';
      return action === 'install_firmware' ? this.command(snapshotArg, requestArg, action, targetEntity, undefined, requestArg.data || {}) : undefined;
    }

    return undefined;
  }

  public static toIntegrationEvent(eventArg: IDevoloEvent): IIntegrationEvent {
    return {
      type: eventArg.type === 'command_failed' || eventArg.type === 'error' || eventArg.error ? 'error' : 'state_changed',
      integrationDomain: devoloHomeNetworkDomain,
      deviceId: eventArg.deviceId,
      entityId: eventArg.entityId,
      data: eventArg,
      timestamp: eventArg.timestamp || Date.now(),
    };
  }

  public static normalizeMac(valueArg?: string): string | undefined {
    if (!valueArg) {
      return undefined;
    }
    const compact = valueArg.replace(/[^0-9a-f]/gi, '').toLowerCase();
    return compact.length === 12 ? compact.match(/.{1,2}/g)?.join(':') : valueArg.toLowerCase();
  }

  public static slug(valueArg: string | undefined): string {
    return (valueArg || devoloHomeNetworkDomain).toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || devoloHomeNetworkDomain;
  }

  private static mergeManualEntries(entriesArg: IDevoloManualEntry[]): {
    device?: IDevoloDeviceInfo;
    plcDevices: IDevoloPlcDevice[];
    plcLinks: IDevoloPlcLink[];
    wifiStations: IDevoloWifiStation[];
    neighboringWifiNetworks: IDevoloNeighborWifiNetwork[];
    firmware?: IDevoloFirmwareUpdate;
    sensors?: IDevoloSensorMap;
    switches?: IDevoloSwitchMap;
    actions: IDevoloActionDescriptor[];
    hasData: boolean;
  } {
    const plcDevices: IDevoloPlcDevice[] = [];
    const plcLinks: IDevoloPlcLink[] = [];
    const wifiStations: IDevoloWifiStation[] = [];
    const neighboringWifiNetworks: IDevoloNeighborWifiNetwork[] = [];
    const actions: IDevoloActionDescriptor[] = [];
    const sensors: IDevoloSensorMap = {};
    const switches: IDevoloSwitchMap = {};
    let device: IDevoloDeviceInfo | undefined;
    let firmware: IDevoloFirmwareUpdate | undefined;
    let hasData = false;

    for (const entry of entriesArg) {
      if (entry.device) {
        device = { ...device, ...entry.device };
        hasData = true;
      } else if (entry.host || entry.ipAddress || entry.name || entry.product || entry.model || entry.serialNumber || entry.macAddress) {
        device = {
          ...device,
          id: entry.id || entry.serialNumber || entry.macAddress || entry.host || entry.ipAddress,
          host: entry.host || entry.ipAddress,
          ipAddress: entry.ipAddress || entry.host,
          port: entry.port,
          name: entry.name,
          hostname: entry.hostname,
          product: entry.product,
          model: entry.model,
          mtNumber: entry.mtNumber,
          serialNumber: entry.serialNumber,
          macAddress: this.normalizeMac(entry.macAddress),
          firmwareVersion: entry.firmwareVersion,
          features: entry.features,
          metadata: entry.metadata,
        };
        hasData = true;
      }

      plcDevices.push(...(entry.plcDevices || []), ...(entry.devices || []));
      plcLinks.push(...(entry.plcLinks || []), ...(entry.links || []), ...(entry.dataRates || []));
      wifiStations.push(...(entry.wifiStations || []), ...(entry.stations || []), ...(entry.clients || []));
      neighboringWifiNetworks.push(...(entry.neighboringWifiNetworks || []), ...(entry.neighbors || []));
      Object.assign(sensors, entry.sensors || {});
      Object.assign(switches, entry.switches || {});
      if (entry.firmware) {
        firmware = { ...firmware, ...entry.firmware };
      }
      actions.push(...(entry.actions || []));
      hasData = hasData || Boolean(entry.snapshot || entry.plcDevices?.length || entry.devices?.length || entry.plcLinks?.length || entry.links?.length || entry.dataRates?.length || entry.wifiStations?.length || entry.stations?.length || entry.clients?.length || entry.neighboringWifiNetworks?.length || entry.neighbors?.length || entry.firmware || entry.sensors || entry.switches || entry.actions?.length);
    }

    return {
      device,
      plcDevices,
      plcLinks,
      wifiStations,
      neighboringWifiNetworks,
      firmware,
      sensors: Object.keys(sensors).length ? sensors : undefined,
      switches: Object.keys(switches).length ? switches : undefined,
      actions,
      hasData,
    };
  }

  private static deviceInfo(configArg: IDevoloConfig, snapshotsArg: IDevoloSnapshot[], manualDeviceArg: IDevoloDeviceInfo | undefined, plcDevicesArg: IDevoloPlcDevice[], plcLinksArg: IDevoloPlcLink[], wifiStationsArg: IDevoloWifiStation[], neighboringWifiNetworksArg: IDevoloNeighborWifiNetwork[]): IDevoloDeviceInfo {
    const sourceDevice = snapshotsArg.find((snapshotArg) => snapshotArg.device)?.device;
    const device = {
      ...sourceDevice,
      ...manualDeviceArg,
      ...configArg.device,
    };
    const host = configArg.host || configArg.ipAddress || device.host || device.ipAddress || sourceDevice?.host || sourceDevice?.ipAddress;
    const port = configArg.port || device.port || (host ? devoloHomeNetworkDefaultPort : undefined);
    const macAddress = this.normalizeMac(configArg.macAddress || device.macAddress || sourceDevice?.macAddress);
    const features = this.uniqueStrings([...(sourceDevice?.features || []), ...(device.features || []), ...(configArg.features || [])]);
    const plcnetApi = configArg.plcnetApi ?? device.plcnetApi ?? sourceDevice?.plcnetApi ?? Boolean(plcDevicesArg.length || plcLinksArg.length);
    const deviceApi = configArg.deviceApi ?? device.deviceApi ?? sourceDevice?.deviceApi ?? Boolean(features.length || wifiStationsArg.length || neighboringWifiNetworksArg.length || configArg.firmware || configArg.switches);
    const id = device.id || configArg.serialNumber || device.serialNumber || macAddress || host || 'device';

    return this.cleanAttributes({
      ...device,
      id,
      host,
      ipAddress: configArg.ipAddress || device.ipAddress || host,
      port,
      name: configArg.name || device.name || this.shortHostname(configArg.hostname || device.hostname) || configArg.product || device.product || 'devolo Home Network',
      hostname: configArg.hostname || device.hostname,
      product: configArg.product || device.product,
      model: configArg.model || device.model || configArg.product || device.product,
      mtNumber: configArg.mtNumber || device.mtNumber,
      serialNumber: configArg.serialNumber || device.serialNumber,
      macAddress,
      firmwareVersion: configArg.firmwareVersion || device.firmwareVersion,
      features,
      deviceApi,
      plcnetApi,
      configurationUrl: device.configurationUrl || (host ? `http://${host}${port && port !== devoloHomeNetworkDefaultPort ? `:${port}` : ''}` : undefined),
      metadata: {
        ...sourceDevice?.metadata,
        ...manualDeviceArg?.metadata,
        ...configArg.device?.metadata,
      },
    }) as IDevoloDeviceInfo;
  }

  private static switches(sourcesArg: Array<IDevoloSnapshot['switches'] | IDevoloSwitchMap | undefined>): IDevoloSnapshot['switches'] {
    let leds: IDevoloSwitchState | undefined;
    let guestWifi: IDevoloGuestWifiState | undefined;
    for (const source of sourcesArg) {
      if (!source) {
        continue;
      }
      const sourceMap = source as IDevoloSwitchMap;
      const ledValue = sourceMap.leds ?? sourceMap.switch_leds;
      const guestValue = sourceMap.guestWifi ?? sourceMap.switch_guest_wifi;
      if (ledValue !== undefined) {
        leds = { ...leds, ...this.switchState(ledValue) };
      }
      if (guestValue !== undefined) {
        guestWifi = { ...guestWifi, ...this.guestWifiState(guestValue) };
      }
    }
    return this.cleanAttributes({ leds, guestWifi }) as IDevoloSnapshot['switches'];
  }

  private static switchState(valueArg: unknown): IDevoloSwitchState {
    if (typeof valueArg === 'boolean') {
      return { enabled: valueArg, available: true };
    }
    if (this.isRecord(valueArg)) {
      return this.cleanAttributes({
        ...valueArg,
        enabled: this.booleanValue(valueArg.enabled ?? valueArg.state ?? valueArg.on),
        available: this.booleanValue(valueArg.available) ?? true,
      }) as IDevoloSwitchState;
    }
    return {};
  }

  private static guestWifiState(valueArg: unknown): IDevoloGuestWifiState {
    if (typeof valueArg === 'boolean') {
      return { enabled: valueArg, available: true };
    }
    if (this.isRecord(valueArg)) {
      return this.cleanAttributes({
        ...valueArg,
        enabled: this.booleanValue(valueArg.enabled ?? valueArg.state ?? valueArg.on),
        ssid: this.stringValue(valueArg.ssid),
        key: this.stringValue(valueArg.key || valueArg.password),
        password: this.stringValue(valueArg.password || valueArg.key),
        available: this.booleanValue(valueArg.available) ?? true,
      }) as IDevoloGuestWifiState;
    }
    return {};
  }

  private static firmware(sourcesArg: Array<IDevoloFirmwareUpdate | undefined>): IDevoloFirmwareUpdate | undefined {
    let firmware: IDevoloFirmwareUpdate | undefined;
    for (const source of sourcesArg) {
      if (source) {
        firmware = { ...firmware, ...source };
      }
    }
    if (!firmware) {
      return undefined;
    }
    const latestVersion = firmware.latestVersion || firmware.newFirmwareVersion;
    const installedVersion = firmware.installedVersion || firmware.currentVersion;
    return this.cleanAttributes({
      ...firmware,
      installedVersion,
      currentVersion: installedVersion,
      latestVersion,
      newFirmwareVersion: firmware.newFirmwareVersion || latestVersion,
      available: firmware.available ?? Boolean(latestVersion && installedVersion && latestVersion !== installedVersion),
    }) as IDevoloFirmwareUpdate;
  }

  private static firmwareFromDevice(deviceArg: IDevoloDeviceInfo): IDevoloFirmwareUpdate | undefined {
    return deviceArg.firmwareVersion ? { installedVersion: deviceArg.firmwareVersion, currentVersion: deviceArg.firmwareVersion } : undefined;
  }

  private static sensorMap(sourcesArg: Array<IDevoloSensorMap | undefined>, deviceArg: IDevoloDeviceInfo, plcDevicesArg: IDevoloPlcDevice[], plcLinksArg: IDevoloPlcLink[], wifiStationsArg: IDevoloWifiStation[], neighboringWifiNetworksArg: IDevoloNeighborWifiNetwork[]): IDevoloSensorMap {
    const sensors: IDevoloSensorMap = {};
    for (const source of sourcesArg) {
      Object.assign(sensors, source || {});
    }
    if (sensors.connected_plc_devices === undefined && (plcDevicesArg.length || plcLinksArg.length || deviceArg.plcnetApi)) {
      const remoteDevices = plcDevicesArg.filter((plcDeviceArg) => !this.isLocalPlcByMac(plcDeviceArg, deviceArg.macAddress));
      sensors.connected_plc_devices = remoteDevices.length || this.uniqueStrings(plcLinksArg.map((linkArg) => this.linkPeerMac(linkArg, deviceArg.macAddress))).length;
    }
    if (sensors.connected_wifi_clients === undefined && (wifiStationsArg.length || this.hasFeature(deviceArg, 'wifi1'))) {
      sensors.connected_wifi_clients = wifiStationsArg.filter((stationArg) => stationArg.connected !== false).length;
    }
    if (sensors.neighboring_wifi_networks === undefined && neighboringWifiNetworksArg.length) {
      sensors.neighboring_wifi_networks = neighboringWifiNetworksArg.length;
    }
    const primaryLink = this.primaryPlcLink({ device: deviceArg, plcLinks: plcLinksArg } as IDevoloSnapshot);
    if (primaryLink) {
      sensors.plc_rx_rate ??= this.linkRxRate(primaryLink);
      sensors.plc_tx_rate ??= this.linkTxRate(primaryLink);
    }
    if (sensors.last_restart === undefined && sensors.uptimeSeconds !== undefined) {
      const uptime = this.numberValue(sensors.uptimeSeconds);
      sensors.last_restart = uptime === undefined ? undefined : new Date(Date.now() - uptime * 1000).toISOString();
    }
    return this.cleanAttributes(sensors) as IDevoloSensorMap;
  }

  private static actionsFromSnapshot(deviceArg: IDevoloDeviceInfo, plcDevicesArg: IDevoloPlcDevice[], plcLinksArg: IDevoloPlcLink[], wifiStationsArg: IDevoloWifiStation[], switchesArg: IDevoloSnapshot['switches'], firmwareArg?: IDevoloFirmwareUpdate): IDevoloActionDescriptor[] {
    const actions: IDevoloActionDescriptor[] = [];
    if (deviceArg.plcnetApi || plcDevicesArg.length || plcLinksArg.length) {
      actions.push(this.actionDescriptor('identify'), this.actionDescriptor('pairing'));
    }
    if (this.hasFeature(deviceArg, 'restart')) {
      actions.push(this.actionDescriptor('restart'));
    }
    if (this.hasFeature(deviceArg, 'wifi1') || wifiStationsArg.length || switchesArg.guestWifi) {
      actions.push(this.actionDescriptor('start_wps'));
    }
    if (this.hasFeature(deviceArg, 'led') || switchesArg.leds) {
      actions.push(this.actionDescriptor('set_leds'));
    }
    if (this.hasFeature(deviceArg, 'wifi1') || switchesArg.guestWifi) {
      actions.push(this.actionDescriptor('set_guest_wifi'));
    }
    if (this.hasFeature(deviceArg, 'update') || firmwareArg) {
      actions.push(this.actionDescriptor('install_firmware'));
    }
    return actions;
  }

  private static actionDescriptor(actionArg: TDevoloActionName): IDevoloActionDescriptor {
    return {
      action: actionArg,
      type: actionTypes[actionArg],
      target: actionArg === 'identify' || actionArg === 'pairing' ? 'plcnet' : actionArg === 'start_wps' || actionArg === 'set_guest_wifi' ? 'wifi' : actionArg === 'install_firmware' ? 'firmware' : 'device',
      platform: actionArg === 'set_leds' || actionArg === 'set_guest_wifi' ? 'switch' : actionArg === 'install_firmware' ? 'update' : 'button',
      available: true,
      requiresPassword: actionArg !== 'identify' && actionArg !== 'pairing',
    };
  }

  private static mainDevice(snapshotArg: IDevoloSnapshot, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'connectivity', value: snapshotArg.connected ? 'online' : 'offline', updatedAt: updatedAtArg },
    ];

    this.addFeatureState(features, state, 'connected_plc_devices', 'Connected PLC Devices', snapshotArg.sensors.connected_plc_devices, updatedAtArg);
    this.addFeatureState(features, state, 'connected_wifi_clients', 'Connected Wi-Fi Clients', snapshotArg.sensors.connected_wifi_clients, updatedAtArg);
    this.addFeatureState(features, state, 'neighboring_wifi_networks', 'Neighboring Wi-Fi Networks', snapshotArg.sensors.neighboring_wifi_networks, updatedAtArg);
    this.addFeatureState(features, state, 'last_restart', 'Last Restart', snapshotArg.sensors.last_restart, updatedAtArg);
    this.addFeatureState(features, state, 'firmware_version', 'Firmware Version', snapshotArg.firmware?.installedVersion || snapshotArg.device.firmwareVersion, updatedAtArg);
    if (snapshotArg.switches.leds || this.hasAction(snapshotArg, 'set_leds')) {
      features.push({ id: 'switch_leds', capability: 'switch', name: 'Enable LEDs', readable: true, writable: true });
      state.push({ featureId: 'switch_leds', value: snapshotArg.switches.leds?.enabled ?? null, updatedAt: updatedAtArg });
    }
    if (snapshotArg.switches.guestWifi || this.hasAction(snapshotArg, 'set_guest_wifi')) {
      features.push({ id: 'switch_guest_wifi', capability: 'switch', name: 'Enable guest Wi-Fi', readable: true, writable: true });
      state.push({ featureId: 'switch_guest_wifi', value: snapshotArg.switches.guestWifi?.enabled ?? null, updatedAt: updatedAtArg });
    }
    if (snapshotArg.firmware || this.hasAction(snapshotArg, 'install_firmware')) {
      features.push({ id: 'firmware_update', capability: 'sensor', name: 'Firmware Update Available', readable: true, writable: false });
      state.push({ featureId: 'firmware_update', value: snapshotArg.firmware?.available ?? false, updatedAt: updatedAtArg });
    }

    return {
      id: this.mainDeviceId(snapshotArg),
      integrationDomain: devoloHomeNetworkDomain,
      name: this.deviceName(snapshotArg.device),
      protocol: 'http',
      manufacturer,
      model: snapshotArg.device.model || snapshotArg.device.product || 'devolo Home Network device',
      online: snapshotArg.connected,
      features: this.uniqueFeatures(features),
      state,
      metadata: this.cleanAttributes({
        host: snapshotArg.device.host || snapshotArg.device.ipAddress,
        port: snapshotArg.device.port || devoloHomeNetworkDefaultPort,
        serialNumber: snapshotArg.device.serialNumber,
        macAddress: snapshotArg.device.macAddress,
        mtNumber: snapshotArg.device.mtNumber,
        firmwareVersion: snapshotArg.device.firmwareVersion,
        configurationUrl: snapshotArg.device.configurationUrl,
        features: snapshotArg.device.features,
        deviceApi: snapshotArg.device.deviceApi,
        plcnetApi: snapshotArg.device.plcnetApi,
        liveHttpImplemented: false,
      }),
    };
  }

  private static plcPeerDevice(snapshotArg: IDevoloSnapshot, deviceArg: IDevoloPlcDevice, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    const link = this.linkForPlcDevice(snapshotArg, deviceArg);
    const attached = this.plcAttachedToRouter(deviceArg);
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'connected_to_router', capability: 'sensor', name: 'Connected to Router', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'connected_to_router', value: attached ?? null, updatedAt: updatedAtArg },
    ];
    if (link) {
      this.addFeatureState(features, state, 'plc_rx_rate', 'PLC downlink PHY rate', this.linkRxRate(link), updatedAtArg, 'Mbit/s');
      this.addFeatureState(features, state, 'plc_tx_rate', 'PLC uplink PHY rate', this.linkTxRate(link), updatedAtArg, 'Mbit/s');
    }

    return {
      id: this.plcDeviceId(deviceArg),
      integrationDomain: devoloHomeNetworkDomain,
      name: this.plcDeviceName(deviceArg),
      protocol: 'unknown',
      manufacturer,
      model: deviceArg.model || deviceArg.product || 'devolo PLC device',
      online: snapshotArg.connected && attached !== false,
      features,
      state,
      metadata: this.cleanAttributes({
        macAddress: this.plcMac(deviceArg),
        topology: deviceArg.topology,
        serialNumber: deviceArg.serialNumber,
        firmwareVersion: deviceArg.firmwareVersion,
        attachedToRouter: attached,
        link: link ? this.cleanAttributes({ fromMac: this.linkFromMac(link), toMac: this.linkToMac(link), rxRate: this.linkRxRate(link), txRate: this.linkTxRate(link) }) : undefined,
      }),
    };
  }

  private static stationDevice(snapshotArg: IDevoloSnapshot, stationArg: IDevoloWifiStation, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    const connected = stationArg.connected !== false && snapshotArg.connected;
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'presence', capability: 'sensor', name: 'Presence', readable: true, writable: false },
      { id: 'ip_address', capability: 'sensor', name: 'IP Address', readable: true, writable: false },
      { id: 'wifi_band', capability: 'sensor', name: 'Wi-Fi Band', readable: true, writable: false },
      { id: 'access_point_type', capability: 'sensor', name: 'Access Point Type', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'presence', value: connected, updatedAt: updatedAtArg },
      { featureId: 'ip_address', value: stationArg.ipAddress || stationArg.ip || null, updatedAt: updatedAtArg },
      { featureId: 'wifi_band', value: this.wifiBand(stationArg.band), updatedAt: updatedAtArg },
      { featureId: 'access_point_type', value: this.vapType(stationArg.vapType ?? stationArg.vap_type), updatedAt: updatedAtArg },
    ];
    const signal = this.numberValue(stationArg.rssi, stationArg.signal);
    if (signal !== undefined) {
      features.push({ id: 'rssi', capability: 'sensor', name: 'RSSI', readable: true, writable: false, unit: 'dBm' });
      state.push({ featureId: 'rssi', value: signal, updatedAt: updatedAtArg });
    }

    return {
      id: this.stationDeviceId(stationArg),
      integrationDomain: devoloHomeNetworkDomain,
      name: this.stationName(stationArg),
      protocol: 'unknown',
      manufacturer: 'Unknown',
      model: 'Wi-Fi station',
      online: connected,
      features,
      state,
      metadata: this.cleanAttributes({
        macAddress: this.stationMac(stationArg),
        ipAddress: stationArg.ipAddress || stationArg.ip,
        ssid: stationArg.ssid,
        vapType: this.vapType(stationArg.vapType ?? stationArg.vap_type),
        band: this.wifiBand(stationArg.band),
        rssi: signal,
      }),
    };
  }

  private static pushCoreSensors(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    const deviceId = this.mainDeviceId(snapshotArg);
    const name = this.deviceName(snapshotArg.device);
    const sensors: Array<[keyof IDevoloSensorMap, string, string | undefined, Record<string, unknown>]> = [
      ['connected_plc_devices', 'Connected PLC devices', undefined, { entityCategory: 'diagnostic', entityRegistryEnabledDefault: false }],
      ['connected_wifi_clients', 'Connected Wi-Fi clients', undefined, { stateClass: 'measurement' }],
      ['neighboring_wifi_networks', 'Neighboring Wi-Fi networks', undefined, { entityCategory: 'diagnostic', entityRegistryEnabledDefault: false }],
      ['last_restart', 'Last restart', undefined, { deviceClass: 'timestamp', entityCategory: 'diagnostic', entityRegistryEnabledDefault: false }],
    ];
    for (const [key, label, unit, attrs] of sensors) {
      const value = snapshotArg.sensors[key];
      if (value === undefined) {
        continue;
      }
      entitiesArg.push(this.entity('sensor', `${name} ${label}`, deviceId, `${this.uniqueBase(snapshotArg)}_${this.slug(String(key))}`, value, usedIdsArg, {
        nativeKey: key,
        unit,
        ...attrs,
      }, snapshotArg.connected, `sensor.${this.slug(name)}_${this.slug(String(key))}`));
    }
  }

  private static pushSwitchEntities(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    const deviceId = this.mainDeviceId(snapshotArg);
    const name = this.deviceName(snapshotArg.device);
    if (snapshotArg.switches.leds || this.hasAction(snapshotArg, 'set_leds')) {
      entitiesArg.push(this.entity('switch', `${name} Enable LEDs`, deviceId, `${this.uniqueBase(snapshotArg)}_switch_leds`, snapshotArg.switches.leds?.enabled ? 'on' : 'off', usedIdsArg, {
        nativeKey: 'switch_leds',
        nativeAction: 'set_leds',
        writable: true,
        entityCategory: 'config',
      }, snapshotArg.connected && snapshotArg.switches.leds?.available !== false));
    }
    if (snapshotArg.switches.guestWifi || this.hasAction(snapshotArg, 'set_guest_wifi')) {
      entitiesArg.push(this.entity('switch', `${name} Enable guest Wi-Fi`, deviceId, `${this.uniqueBase(snapshotArg)}_switch_guest_wifi`, snapshotArg.switches.guestWifi?.enabled ? 'on' : 'off', usedIdsArg, {
        nativeKey: 'switch_guest_wifi',
        nativeAction: 'set_guest_wifi',
        writable: true,
        ssid: snapshotArg.switches.guestWifi?.ssid,
        keyConfigured: Boolean(snapshotArg.switches.guestWifi?.key || snapshotArg.switches.guestWifi?.password),
      }, snapshotArg.connected && snapshotArg.switches.guestWifi?.available !== false));
    }
  }

  private static pushButtonEntities(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    const deviceId = this.mainDeviceId(snapshotArg);
    const name = this.deviceName(snapshotArg.device);
    for (const action of snapshotArg.actions) {
      if (action.platform !== 'button' || !['identify', 'pairing', 'restart', 'start_wps'].includes(action.action)) {
        continue;
      }
      entitiesArg.push(this.entity('button', `${name} ${actionLabels[action.action]}`, deviceId, `${this.uniqueBase(snapshotArg)}_${action.action}`, null, usedIdsArg, {
        nativeAction: action.action,
        commandType: action.type,
        target: action.target,
        entityCategory: action.action === 'identify' ? 'diagnostic' : action.action === 'restart' ? 'config' : undefined,
        requiresPassword: action.requiresPassword,
      }, snapshotArg.connected && action.available !== false));
    }
  }

  private static pushFirmwareEntity(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    if (!snapshotArg.firmware && !this.hasAction(snapshotArg, 'install_firmware')) {
      return;
    }
    const firmware = snapshotArg.firmware || {};
    const name = this.deviceName(snapshotArg.device);
    entitiesArg.push(this.entity('update', `${name} Regular firmware`, this.mainDeviceId(snapshotArg), `${this.uniqueBase(snapshotArg)}_regular_firmware`, firmware.available ? 'on' : 'off', usedIdsArg, {
      nativeKey: 'regular_firmware',
      nativeAction: 'install_firmware',
      deviceClass: 'firmware',
      entityCategory: 'config',
      installedVersion: firmware.installedVersion || firmware.currentVersion || snapshotArg.device.firmwareVersion,
      latestVersion: firmware.latestVersion || firmware.newFirmwareVersion || firmware.installedVersion || snapshotArg.device.firmwareVersion,
      inProgress: firmware.inProgress === true,
      releaseUrl: firmware.releaseUrl,
      supportedFeatures: ['install', 'progress'],
    }, snapshotArg.connected));
  }

  private static pushPlcLinkEntities(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    const deviceName = this.deviceName(snapshotArg.device);
    const localMac = snapshotArg.device.macAddress;
    for (const link of snapshotArg.plcLinks) {
      const peerMac = this.linkPeerMac(link, localMac) || this.linkToMac(link);
      const peer = snapshotArg.plcDevices.find((deviceArg) => this.plcMac(deviceArg) === peerMac);
      const peerName = peer ? this.plcDeviceName(peer) : peerMac || 'PLC peer';
      const suffix = this.slug(peerName || peerMac);
      const attrs = {
        nativeKey: 'plc_rate',
        entityCategory: 'diagnostic',
        deviceClass: 'data_rate',
        unit: 'Mbit/s',
        peerMac,
        localMac,
      };
      const rx = this.linkRxRate(link);
      if (rx !== undefined) {
        entitiesArg.push(this.entity('sensor', `${deviceName} PLC downlink PHY rate (${peerName})`, this.mainDeviceId(snapshotArg), `${this.uniqueBase(snapshotArg)}_plc_rx_rate_${suffix}`, rx, usedIdsArg, attrs, snapshotArg.connected));
      }
      const tx = this.linkTxRate(link);
      if (tx !== undefined) {
        entitiesArg.push(this.entity('sensor', `${deviceName} PLC uplink PHY rate (${peerName})`, this.mainDeviceId(snapshotArg), `${this.uniqueBase(snapshotArg)}_plc_tx_rate_${suffix}`, tx, usedIdsArg, attrs, snapshotArg.connected));
      }
    }
  }

  private static pushStationEntities(entitiesArg: IIntegrationEntity[], snapshotArg: IDevoloSnapshot, usedIdsArg: Map<string, number>): void {
    for (const station of snapshotArg.wifiStations) {
      const name = this.stationName(station);
      const deviceId = this.stationDeviceId(station);
      const mac = this.stationMac(station);
      const connected = station.connected !== false && snapshotArg.connected;
      entitiesArg.push(this.entity('binary_sensor', `${name} Connected`, deviceId, `devolo_station_${this.slug(mac || name)}_connected`, connected ? 'on' : 'off', usedIdsArg, {
        deviceClass: 'connectivity',
        macAddress: mac,
        ipAddress: station.ipAddress || station.ip,
        ssid: station.ssid,
      }, snapshotArg.connected));
      if (station.ipAddress || station.ip) {
        entitiesArg.push(this.entity('sensor', `${name} IP address`, deviceId, `devolo_station_${this.slug(mac || name)}_ip`, station.ipAddress || station.ip, usedIdsArg, { nativeKey: 'ip_address', macAddress: mac }, connected));
      }
      entitiesArg.push(this.entity('sensor', `${name} Wi-Fi band`, deviceId, `devolo_station_${this.slug(mac || name)}_band`, this.wifiBand(station.band), usedIdsArg, { nativeKey: 'band', macAddress: mac, unit: this.wifiBand(station.band) === 'unknown' ? undefined : 'GHz' }, connected));
      entitiesArg.push(this.entity('sensor', `${name} access point type`, deviceId, `devolo_station_${this.slug(mac || name)}_vap`, this.vapType(station.vapType ?? station.vap_type), usedIdsArg, { nativeKey: 'vap_type', macAddress: mac }, connected));
      const rssi = this.numberValue(station.rssi, station.signal);
      if (rssi !== undefined) {
        entitiesArg.push(this.entity('sensor', `${name} RSSI`, deviceId, `devolo_station_${this.slug(mac || name)}_rssi`, rssi, usedIdsArg, { nativeKey: 'rssi', macAddress: mac, unit: 'dBm' }, connected));
      }
    }
  }

  private static command(snapshotArg: IDevoloSnapshot, requestArg: IServiceCallRequest, actionArg: TDevoloActionName, entityArg?: IIntegrationEntity, enabledArg?: boolean, payloadArg: Record<string, unknown> = {}): IDevoloCommand | undefined {
    const action = snapshotArg.actions.find((actionEntryArg) => actionEntryArg.action === actionArg);
    if (!action || action.available === false) {
      return undefined;
    }
    return {
      type: action.type,
      action: action.action,
      service: requestArg.service,
      target: requestArg.target,
      deviceId: entityArg?.deviceId || action.deviceId || requestArg.target.deviceId || this.mainDeviceId(snapshotArg),
      entityId: entityArg?.id || action.entityId || requestArg.target.entityId,
      enabled: enabledArg,
      requiresPassword: action.requiresPassword,
      payload: this.cleanAttributes({ ...payloadArg, enabled: enabledArg }) as Record<string, unknown>,
    };
  }

  private static actionFromDomainService(serviceArg: string): TDevoloActionName | undefined {
    if (serviceArg === 'identify') return 'identify';
    if (serviceArg === 'pairing' || serviceArg === 'pair_device' || serviceArg === 'start_pairing') return 'pairing';
    if (serviceArg === 'restart' || serviceArg === 'reboot') return 'restart';
    if (serviceArg === 'start_wps') return 'start_wps';
    if (serviceArg === 'set_leds') return 'set_leds';
    if (serviceArg === 'set_guest_wifi' || serviceArg === 'set_wifi_guest_access') return 'set_guest_wifi';
    if (serviceArg === 'install_firmware' || serviceArg === 'start_firmware_update') return 'install_firmware';
    return undefined;
  }

  private static actionValue(valueArg: unknown): TDevoloActionName | undefined {
    if (typeof valueArg !== 'string') {
      return undefined;
    }
    return ['identify', 'pairing', 'restart', 'start_wps', 'set_leds', 'set_guest_wifi', 'install_firmware'].includes(valueArg) ? valueArg as TDevoloActionName : undefined;
  }

  private static findTargetEntity(snapshotArg: IDevoloSnapshot, requestArg: IServiceCallRequest): IIntegrationEntity | undefined {
    const entities = this.toEntities(snapshotArg);
    if (requestArg.target.entityId) {
      return entities.find((entityArg) => entityArg.id === requestArg.target.entityId || entityArg.uniqueId === requestArg.target.entityId);
    }
    if (requestArg.target.deviceId) {
      return entities.find((entityArg) => entityArg.deviceId === requestArg.target.deviceId && entityArg.platform === requestArg.domain);
    }
    return undefined;
  }

  private static entity(platformArg: TEntityPlatform, nameArg: string, deviceIdArg: string, uniqueIdArg: string, stateArg: unknown, usedIdsArg: Map<string, number>, attributesArg?: Record<string, unknown>, availableArg = true, entityIdArg?: string): IIntegrationEntity {
    const baseId = entityIdArg || `${platformArg}.${this.slug(nameArg)}`;
    const current = usedIdsArg.get(baseId) || 0;
    usedIdsArg.set(baseId, current + 1);
    const id = current ? `${baseId}_${current + 1}` : baseId;
    return {
      id,
      uniqueId: uniqueIdArg,
      integrationDomain: devoloHomeNetworkDomain,
      deviceId: deviceIdArg,
      platform: platformArg,
      name: nameArg,
      state: this.entityState(stateArg, platformArg),
      attributes: this.cleanAttributes(attributesArg || {}),
      available: availableArg,
    };
  }

  private static entityState(valueArg: unknown, platformArg: TEntityPlatform): unknown {
    if (platformArg === 'binary_sensor' || platformArg === 'switch') {
      const value = this.booleanValue(valueArg);
      return value ? 'on' : 'off';
    }
    return valueArg ?? null;
  }

  private static mainDeviceId(snapshotArg: IDevoloSnapshot): string {
    const key = snapshotArg.device.serialNumber || snapshotArg.device.macAddress || snapshotArg.device.id || snapshotArg.device.host || snapshotArg.device.ipAddress || 'device';
    return `${devoloHomeNetworkDomain}.device.${this.slug(key)}`;
  }

  private static plcDeviceId(deviceArg: IDevoloPlcDevice): string {
    return `${devoloHomeNetworkDomain}.plc.${this.slug(this.plcMac(deviceArg) || deviceArg.id || this.plcDeviceName(deviceArg))}`;
  }

  private static stationDeviceId(stationArg: IDevoloWifiStation): string {
    return `${devoloHomeNetworkDomain}.station.${this.slug(this.stationMac(stationArg) || stationArg.id || this.stationName(stationArg))}`;
  }

  private static uniqueBase(snapshotArg: IDevoloSnapshot): string {
    return `${devoloHomeNetworkDomain}_${this.slug(snapshotArg.device.serialNumber || snapshotArg.device.macAddress || snapshotArg.device.id || snapshotArg.device.host || 'device')}`;
  }

  private static deviceName(deviceArg: IDevoloDeviceInfo): string {
    return deviceArg.name || this.shortHostname(deviceArg.hostname) || deviceArg.product || deviceArg.model || deviceArg.host || 'devolo Home Network';
  }

  private static plcDeviceName(deviceArg: IDevoloPlcDevice): string {
    return deviceArg.userDeviceName || deviceArg.user_device_name || deviceArg.name || this.plcMac(deviceArg) || 'PLC device';
  }

  private static stationName(stationArg: IDevoloWifiStation): string {
    return stationArg.name || stationArg.hostname || stationArg.ipAddress || stationArg.ip || this.stationMac(stationArg) || 'Wi-Fi station';
  }

  private static plcMac(deviceArg: IDevoloPlcDevice): string | undefined {
    return this.normalizeMac(deviceArg.macAddress || deviceArg.mac_address);
  }

  private static stationMac(stationArg: IDevoloWifiStation): string | undefined {
    return this.normalizeMac(stationArg.macAddress || stationArg.mac_address);
  }

  private static linkFromMac(linkArg: IDevoloPlcLink): string | undefined {
    return this.normalizeMac(linkArg.fromMac || linkArg.macAddressFrom || linkArg.mac_address_from);
  }

  private static linkToMac(linkArg: IDevoloPlcLink): string | undefined {
    return this.normalizeMac(linkArg.toMac || linkArg.macAddressTo || linkArg.mac_address_to);
  }

  private static linkRxRate(linkArg: IDevoloPlcLink): number | undefined {
    return this.numberValue(linkArg.rxRate, linkArg.rx_rate);
  }

  private static linkTxRate(linkArg: IDevoloPlcLink): number | undefined {
    return this.numberValue(linkArg.txRate, linkArg.tx_rate);
  }

  private static linkPeerMac(linkArg: IDevoloPlcLink, localMacArg?: string): string | undefined {
    const from = this.linkFromMac(linkArg);
    const to = this.linkToMac(linkArg);
    const local = this.normalizeMac(localMacArg);
    if (local && from === local) return to;
    if (local && to === local) return from;
    return to || from;
  }

  private static primaryPlcLink(snapshotArg: Pick<IDevoloSnapshot, 'device' | 'plcLinks'>): IDevoloPlcLink | undefined {
    const localMac = this.normalizeMac(snapshotArg.device.macAddress);
    return snapshotArg.plcLinks.find((linkArg) => !localMac || this.linkFromMac(linkArg) === localMac || this.linkToMac(linkArg) === localMac);
  }

  private static linkForPlcDevice(snapshotArg: IDevoloSnapshot, deviceArg: IDevoloPlcDevice): IDevoloPlcLink | undefined {
    const mac = this.plcMac(deviceArg);
    return snapshotArg.plcLinks.find((linkArg) => this.linkFromMac(linkArg) === mac || this.linkToMac(linkArg) === mac);
  }

  private static connectedToRouter(snapshotArg: IDevoloSnapshot): boolean | undefined {
    const localMac = this.normalizeMac(snapshotArg.device.macAddress);
    if (!localMac) {
      return undefined;
    }
    const localDevice = snapshotArg.plcDevices.find((deviceArg) => this.plcMac(deviceArg) === localMac);
    return localDevice ? this.plcAttachedToRouter(localDevice) : undefined;
  }

  private static plcAttachedToRouter(deviceArg: IDevoloPlcDevice): boolean | undefined {
    return this.booleanValue(deviceArg.attachedToRouter ?? deviceArg.attached_to_router);
  }

  private static isLocalPlcDevice(snapshotArg: IDevoloSnapshot, deviceArg: IDevoloPlcDevice): boolean {
    const mac = this.plcMac(deviceArg);
    return this.isLocalPlcByMac(deviceArg, snapshotArg.device.macAddress) || Boolean(mac && mac === this.normalizeMac(snapshotArg.device.macAddress));
  }

  private static isLocalPlcByMac(deviceArg: IDevoloPlcDevice, localMacArg?: string): boolean {
    const topology = String(deviceArg.topology || '').toLowerCase();
    const mac = this.plcMac(deviceArg);
    const localMac = this.normalizeMac(localMacArg);
    return topology === 'local' || Boolean(mac && localMac && mac === localMac);
  }

  private static hasFeature(deviceArg: IDevoloDeviceInfo, featureArg: string): boolean {
    return (deviceArg.features || []).some((entryArg) => String(entryArg).toLowerCase() === featureArg.toLowerCase());
  }

  private static hasAction(snapshotArg: IDevoloSnapshot, actionArg: TDevoloActionName): boolean {
    return snapshotArg.actions.some((actionEntryArg) => actionEntryArg.action === actionArg && actionEntryArg.available !== false);
  }

  private static wifiBand(valueArg: unknown): string {
    if (valueArg === 0 || valueArg === '0' || valueArg === '2' || valueArg === '2g' || valueArg === '2.4' || valueArg === 2.4) {
      return '2.4';
    }
    if (valueArg === 1 || valueArg === '1' || valueArg === '5' || valueArg === '5g' || valueArg === 5) {
      return '5';
    }
    return this.stringValue(valueArg) || 'unknown';
  }

  private static vapType(valueArg: unknown): string {
    if (valueArg === 0 || valueArg === '0' || String(valueArg).toLowerCase() === 'main') {
      return 'Main';
    }
    if (valueArg === 1 || valueArg === '1' || String(valueArg).toLowerCase() === 'guest') {
      return 'Guest';
    }
    return this.stringValue(valueArg) || 'unknown';
  }

  private static uniquePlcDevices(devicesArg: IDevoloPlcDevice[]): IDevoloPlcDevice[] {
    const seen = new Set<string>();
    return devicesArg.filter((deviceArg) => {
      const key = this.plcMac(deviceArg) || deviceArg.id || this.plcDeviceName(deviceArg);
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }

  private static uniquePlcLinks(linksArg: IDevoloPlcLink[]): IDevoloPlcLink[] {
    const seen = new Set<string>();
    return linksArg.filter((linkArg) => {
      const key = linkArg.id || `${this.linkFromMac(linkArg) || 'from'}>${this.linkToMac(linkArg) || 'to'}`;
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }

  private static uniqueWifiStations(stationsArg: IDevoloWifiStation[]): IDevoloWifiStation[] {
    const seen = new Set<string>();
    return stationsArg.filter((stationArg) => {
      const key = this.stationMac(stationArg) || stationArg.id || this.stationName(stationArg);
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }

  private static uniqueNeighborNetworks(networksArg: IDevoloNeighborWifiNetwork[]): IDevoloNeighborWifiNetwork[] {
    const seen = new Set<string>();
    return networksArg.filter((networkArg) => {
      const key = networkArg.id || this.normalizeMac(networkArg.bssid || networkArg.macAddress) || `${networkArg.ssid || 'ssid'}:${networkArg.channel || ''}:${networkArg.band || ''}`;
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }

  private static uniqueActions(actionsArg: IDevoloActionDescriptor[]): IDevoloActionDescriptor[] {
    const seen = new Set<string>();
    return actionsArg.filter((actionArg) => {
      const key = `${actionArg.action}:${actionArg.entityId || ''}:${actionArg.deviceId || ''}`;
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }

  private static uniqueDeviceDefinitions(devicesArg: plugins.shxInterfaces.data.IDeviceDefinition[]): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const seen = new Set<string>();
    return devicesArg.filter((deviceArg) => {
      if (seen.has(deviceArg.id)) return false;
      seen.add(deviceArg.id);
      return true;
    });
  }

  private static uniqueFeatures(featuresArg: plugins.shxInterfaces.data.IDeviceFeature[]): plugins.shxInterfaces.data.IDeviceFeature[] {
    const seen = new Set<string>();
    return featuresArg.filter((featureArg) => {
      if (seen.has(featureArg.id)) return false;
      seen.add(featureArg.id);
      return true;
    });
  }

  private static uniqueStrings(valuesArg: Array<string | undefined>): string[] {
    return [...new Set(valuesArg.filter((valueArg): valueArg is string => Boolean(valueArg)))];
  }

  private static addFeatureState(featuresArg: plugins.shxInterfaces.data.IDeviceFeature[], stateArg: plugins.shxInterfaces.data.IDeviceState[], idArg: string, nameArg: string, valueArg: unknown, updatedAtArg: string, unitArg?: string): void {
    if (valueArg === undefined) {
      return;
    }
    featuresArg.push({ id: idArg, capability: 'sensor', name: nameArg, readable: true, writable: false, unit: unitArg });
    stateArg.push({ featureId: idArg, value: this.deviceStateValue(valueArg), updatedAt: updatedAtArg });
  }

  private static deviceStateValue(valueArg: unknown): plugins.shxInterfaces.data.TDeviceStateValue {
    if (typeof valueArg === 'string' || typeof valueArg === 'number' || typeof valueArg === 'boolean' || valueArg === null) {
      return valueArg;
    }
    if (this.isRecord(valueArg)) {
      return valueArg;
    }
    return valueArg === undefined ? null : String(valueArg);
  }

  private static booleanValue(valueArg: unknown): boolean | undefined {
    if (typeof valueArg === 'boolean') return valueArg;
    if (typeof valueArg === 'number') return valueArg !== 0;
    if (typeof valueArg === 'string') {
      const value = valueArg.trim().toLowerCase();
      if (['true', 'on', 'yes', '1', 'enabled', 'enable'].includes(value)) return true;
      if (['false', 'off', 'no', '0', 'disabled', 'disable'].includes(value)) return false;
    }
    return undefined;
  }

  private static numberValue(...valuesArg: unknown[]): number | undefined {
    for (const value of valuesArg) {
      if (typeof value === 'number' && Number.isFinite(value)) return value;
      if (typeof value === 'string' && value.trim()) {
        const parsed = Number(value);
        if (Number.isFinite(parsed)) return parsed;
      }
    }
    return undefined;
  }

  private static stringValue(valueArg: unknown): string | undefined {
    return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
  }

  private static shortHostname(valueArg?: string): string | undefined {
    return valueArg?.split('.')[0];
  }

  private static isRecord(valueArg: unknown): valueArg is Record<string, unknown> {
    return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
  }

  private static cleanAttributes<TValue>(valueArg: TValue): TValue {
    if (!this.isRecord(valueArg)) {
      return valueArg;
    }
    return Object.fromEntries(Object.entries(valueArg).filter(([, value]) => value !== undefined)) as TValue;
  }
}

export const DevoloMapper = DevoloHomeNetworkMapper;
