import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IIntegrationEvent, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
import type {
  IUnifiClient,
  IUnifiCommand,
  IUnifiConfig,
  IUnifiDevice,
  IUnifiEvent,
  IUnifiPort,
  IUnifiSnapshot,
  IUnifiWlan,
} from './unifi.types.js';
import { unifiDefaultPort, unifiDefaultSite } from './unifi.types.js';

const manufacturer = 'Ubiquiti Networks';
const connectedDeviceState = 1;

export class UnifiMapper {
  public static toSnapshot(configArg: IUnifiConfig, connectedArg?: boolean, eventsArg: IUnifiEvent[] = []): IUnifiSnapshot {
    const source = configArg.snapshot;
    const devices = [...(source?.devices || []), ...(configArg.devices || [])];
    const ports = [...(source?.ports || []), ...(configArg.ports || [])];

    for (const entry of configArg.manualEntries || []) {
      if (entry.snapshot) {
        devices.push(...entry.snapshot.devices);
        ports.push(...entry.snapshot.ports);
      } else {
        devices.push(...(entry.devices || []));
        ports.push(...(entry.ports || []));
      }
    }

    const snapshot: IUnifiSnapshot = {
      connected: connectedArg ?? source?.connected ?? Boolean(configArg.host && configArg.username),
      host: configArg.host || source?.host,
      port: configArg.port || source?.port || unifiDefaultPort,
      site: configArg.site || source?.site || unifiDefaultSite,
      controller: {
        ...source?.controller,
        ...configArg.controller,
        host: configArg.host || configArg.controller?.host || source?.controller?.host || source?.host,
        port: configArg.port || configArg.controller?.port || source?.controller?.port || source?.port || unifiDefaultPort,
        site: configArg.site || configArg.controller?.site || source?.controller?.site || source?.site || unifiDefaultSite,
        connected: connectedArg ?? source?.controller?.connected ?? source?.connected,
      },
      sites: [
        ...(source?.sites || []),
        ...(configArg.sites || []),
        ...this.manualItems(configArg, 'sites'),
      ],
      clients: [
        ...(source?.clients || []),
        ...(configArg.clients || []),
        ...this.manualItems(configArg, 'clients'),
      ],
      devices,
      wlans: [
        ...(source?.wlans || []),
        ...(configArg.wlans || []),
        ...this.manualItems(configArg, 'wlans'),
      ],
      ports,
      events: [...(source?.events || []), ...(configArg.events || []), ...eventsArg],
    };

    snapshot.ports = this.withDerivedPorts(snapshot);
    return snapshot;
  }

  public static toDevices(snapshotArg: IUnifiSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = new Date().toISOString();
    const devices: plugins.shxInterfaces.data.IDeviceDefinition[] = [];

    if (snapshotArg.controller || snapshotArg.host) {
      const controller = snapshotArg.controller || {};
      const id = `unifi.controller.${this.slug(controller.id || controller.host || snapshotArg.host || snapshotArg.site || 'default')}`;
      devices.push({
        id,
        integrationDomain: 'unifi',
        name: controller.name || 'UniFi Network',
        protocol: 'http',
        manufacturer,
        model: controller.deviceType || 'UniFi Network Application',
        online: snapshotArg.connected,
        features: [
          { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
          { id: 'version', capability: 'sensor', name: 'Version', readable: true, writable: false },
        ],
        state: [
          { featureId: 'connectivity', value: snapshotArg.connected ? 'online' : 'offline', updatedAt },
          { featureId: 'version', value: controller.version || null, updatedAt },
        ],
        metadata: {
          host: controller.host || snapshotArg.host,
          port: controller.port || snapshotArg.port,
          site: controller.site || snapshotArg.site,
          unifiOs: controller.isUnifiOs,
        },
      });
    }

    for (const device of snapshotArg.devices) {
      devices.push(this.infrastructureDevice(device, snapshotArg, updatedAt));
    }

    for (const client of snapshotArg.clients) {
      devices.push(this.clientDevice(client, updatedAt));
    }

    for (const wlan of snapshotArg.wlans) {
      devices.push(this.wlanDevice(wlan, snapshotArg, updatedAt));
    }

    return devices;
  }

  public static toEntities(snapshotArg: IUnifiSnapshot): IIntegrationEntity[] {
    const entities: IIntegrationEntity[] = [];
    const usedIds = new Map<string, number>();

    if (snapshotArg.controller || snapshotArg.host) {
      const controller = snapshotArg.controller || {};
      const deviceId = `unifi.controller.${this.slug(controller.id || controller.host || snapshotArg.host || snapshotArg.site || 'default')}`;
      entities.push(this.entity('binary_sensor', 'UniFi Network Connected', deviceId, 'unifi_controller_connected', snapshotArg.connected ? 'on' : 'off', usedIds, {
        deviceClass: 'connectivity',
        host: controller.host || snapshotArg.host,
        port: controller.port || snapshotArg.port,
        site: controller.site || snapshotArg.site,
      }, true));
      if (controller.version) {
        entities.push(this.entity('sensor', 'UniFi Network Version', deviceId, 'unifi_controller_version', controller.version, usedIds, undefined, snapshotArg.connected));
      }
    }

    for (const client of snapshotArg.clients) {
      this.pushClientEntities(entities, client, usedIds);
    }

    for (const device of snapshotArg.devices) {
      this.pushDeviceEntities(entities, device, snapshotArg, usedIds);
    }

    for (const wlan of snapshotArg.wlans) {
      this.pushWlanEntities(entities, wlan, snapshotArg, usedIds);
    }

    for (const port of this.withDerivedPorts(snapshotArg)) {
      this.pushPortEntities(entities, port, snapshotArg, usedIds);
    }

    return entities;
  }

  public static commandForService(snapshotArg: IUnifiSnapshot, requestArg: IServiceCallRequest): IUnifiCommand | undefined {
    if (requestArg.domain === 'unifi') {
      const mac = this.stringValue(requestArg.data?.mac) || this.macFromTarget(snapshotArg, requestArg);
      if ((requestArg.service === 'block_client' || requestArg.service === 'unblock_client') && mac) {
        return {
          type: 'blockClient',
          service: requestArg.service,
          target: requestArg.target,
          mac,
          block: requestArg.service === 'block_client',
        };
      }
      if (requestArg.service === 'reconnect_client' && mac) {
        return {
          type: 'reconnectClient',
          service: requestArg.service,
          target: requestArg.target,
          mac,
        };
      }
      if ((requestArg.service === 'enable_wlan' || requestArg.service === 'disable_wlan') && this.stringValue(requestArg.data?.wlanId)) {
        return {
          type: 'setWlanEnabled',
          service: requestArg.service,
          target: requestArg.target,
          wlanId: this.stringValue(requestArg.data?.wlanId),
          enabled: requestArg.service === 'enable_wlan',
        };
      }
      if ((requestArg.service === 'enable_poe' || requestArg.service === 'disable_poe') && this.stringValue(requestArg.data?.deviceMac) && requestArg.data?.portIdx !== undefined) {
        return {
          type: 'setPoePortEnabled',
          service: requestArg.service,
          target: requestArg.target,
          deviceMac: this.stringValue(requestArg.data.deviceMac),
          portIdx: this.stringValue(requestArg.data.portIdx),
          enabled: requestArg.service === 'enable_poe',
        };
      }
    }

    if (requestArg.domain !== 'switch' || !['turn_on', 'turn_off'].includes(requestArg.service)) {
      return undefined;
    }

    const target = this.findTargetEntity(snapshotArg, requestArg);
    if (!target) {
      return undefined;
    }
    const enabled = requestArg.service === 'turn_on';

    if (target.attributes?.nativeType === 'wlan') {
      return {
        type: 'setWlanEnabled',
        service: requestArg.service,
        target: requestArg.target,
        wlanId: this.stringValue(target.attributes.wlanId),
        enabled,
      };
    }

    if (target.attributes?.nativeType === 'poe_port') {
      return {
        type: 'setPoePortEnabled',
        service: requestArg.service,
        target: requestArg.target,
        deviceMac: this.stringValue(target.attributes.deviceMac),
        portIdx: this.stringValue(target.attributes.portIdx),
        enabled,
      };
    }

    if (target.attributes?.nativeType === 'client_access') {
      return {
        type: 'blockClient',
        service: requestArg.service,
        target: requestArg.target,
        mac: this.stringValue(target.attributes.mac),
        block: !enabled,
      };
    }

    return undefined;
  }

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

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

  private static infrastructureDevice(deviceArg: IUnifiDevice, snapshotArg: IUnifiSnapshot, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    const deviceId = this.deviceId(deviceArg);
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
      { id: 'client_count', capability: 'sensor', name: 'Clients', readable: true, writable: false },
      { id: 'state', capability: 'sensor', name: 'State', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'connectivity', value: this.deviceConnected(deviceArg) ? 'online' : 'offline', updatedAt: updatedAtArg },
      { featureId: 'client_count', value: this.clientsForDevice(snapshotArg, deviceArg), updatedAt: updatedAtArg },
      { featureId: 'state', value: this.deviceState(deviceArg), updatedAt: updatedAtArg },
    ];
    const temperature = this.numberValue(deviceArg.generalTemperature, deviceArg.general_temperature);
    if (temperature !== undefined || deviceArg.hasTemperature || deviceArg.has_temperature) {
      features.push({ id: 'temperature', capability: 'sensor', name: 'Temperature', readable: true, writable: false, unit: 'C' });
      state.push({ featureId: 'temperature', value: temperature ?? null, updatedAt: updatedAtArg });
    }
    for (const port of this.portsForDevice(snapshotArg, deviceArg)) {
      const portKey = this.portKey(port);
      features.push({ id: `port_${portKey}_link`, capability: 'sensor', name: `${this.portName(port)} link`, readable: true, writable: false });
      state.push({ featureId: `port_${portKey}_link`, value: this.booleanValue(port.up) ?? false, updatedAt: updatedAtArg });
      if (this.portHasPoe(port)) {
        features.push({ id: `port_${portKey}_poe`, capability: 'switch', name: `${this.portName(port)} PoE`, readable: true, writable: true });
        state.push({ featureId: `port_${portKey}_poe`, value: this.portPoeEnabled(port), updatedAt: updatedAtArg });
      }
    }
    return {
      id: deviceId,
      integrationDomain: 'unifi',
      name: this.deviceName(deviceArg),
      protocol: 'http',
      manufacturer,
      model: deviceArg.model || deviceArg.type || 'UniFi device',
      online: this.deviceConnected(deviceArg),
      features,
      state,
      metadata: {
        mac: this.normalizeMac(deviceArg.mac),
        ip: deviceArg.ip,
        version: deviceArg.version,
        type: deviceArg.type,
        boardRevision: deviceArg.boardRevision ?? deviceArg.board_rev,
      },
    };
  }

  private static clientDevice(clientArg: IUnifiClient, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'presence', capability: 'sensor', name: 'Presence', readable: true, writable: false },
      { id: 'blocked', capability: 'switch', name: 'Network access', readable: true, writable: true },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'presence', value: this.clientConnected(clientArg), updatedAt: updatedAtArg },
      { featureId: 'blocked', value: !this.booleanValue(clientArg.blocked), updatedAt: updatedAtArg },
    ];
    const rx = this.clientRx(clientArg);
    const tx = this.clientTx(clientArg);
    if (rx !== undefined) {
      features.push({ id: 'rx_rate', capability: 'sensor', name: 'RX rate', readable: true, writable: false, unit: 'MB/s' });
      state.push({ featureId: 'rx_rate', value: rx, updatedAt: updatedAtArg });
    }
    if (tx !== undefined) {
      features.push({ id: 'tx_rate', capability: 'sensor', name: 'TX rate', readable: true, writable: false, unit: 'MB/s' });
      state.push({ featureId: 'tx_rate', value: tx, updatedAt: updatedAtArg });
    }
    return {
      id: this.clientDeviceId(clientArg),
      integrationDomain: 'unifi',
      name: this.clientName(clientArg),
      protocol: 'unknown',
      manufacturer: clientArg.oui || 'Unknown',
      model: clientArg.deviceName || clientArg.device_name || 'Network client',
      online: this.clientConnected(clientArg),
      features,
      state,
      metadata: {
        mac: this.normalizeMac(clientArg.mac),
        ip: clientArg.ip,
        essid: clientArg.essid,
        wired: this.clientWired(clientArg),
        guest: this.booleanValue(clientArg.isGuest, clientArg.is_guest),
      },
    };
  }

  private static wlanDevice(wlanArg: IUnifiWlan, snapshotArg: IUnifiSnapshot, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
    return {
      id: this.wlanDeviceId(wlanArg),
      integrationDomain: 'unifi',
      name: wlanArg.name,
      protocol: 'http',
      manufacturer,
      model: 'UniFi WLAN',
      online: this.booleanValue(wlanArg.enabled) !== false,
      features: [
        { id: 'enabled', capability: 'switch', name: 'Enabled', readable: true, writable: true },
        { id: 'clients', capability: 'sensor', name: 'Clients', readable: true, writable: false },
      ],
      state: [
        { featureId: 'enabled', value: this.booleanValue(wlanArg.enabled) ?? true, updatedAt: updatedAtArg },
        { featureId: 'clients', value: this.clientsForWlan(snapshotArg, wlanArg), updatedAt: updatedAtArg },
      ],
      metadata: {
        wlanId: this.wlanId(wlanArg),
        siteId: wlanArg.siteId || wlanArg.site_id,
        security: wlanArg.security,
        guest: this.booleanValue(wlanArg.isGuest, wlanArg.is_guest),
      },
    };
  }

  private static pushClientEntities(entitiesArg: IIntegrationEntity[], clientArg: IUnifiClient, usedIdsArg: Map<string, number>): void {
    const name = this.clientName(clientArg);
    const deviceId = this.clientDeviceId(clientArg);
    const mac = this.normalizeMac(clientArg.mac) || clientArg.mac;
    const connected = this.clientConnected(clientArg);
    entitiesArg.push(this.entity('binary_sensor', `${name} Connected`, deviceId, `unifi_client_connected_${this.slug(mac)}`, connected ? 'on' : 'off', usedIdsArg, {
      deviceClass: 'connectivity',
      mac,
      ip: clientArg.ip,
      essid: clientArg.essid,
      wired: this.clientWired(clientArg),
    }, true));
    entitiesArg.push(this.entity('switch', `${name} Network Access`, deviceId, `unifi_client_access_${this.slug(mac)}`, clientArg.blocked ? 'off' : 'on', usedIdsArg, {
      nativeType: 'client_access',
      mac,
      writable: true,
    }, true));
    if (clientArg.ip) {
      entitiesArg.push(this.entity('sensor', `${name} IP`, deviceId, `unifi_client_ip_${this.slug(mac)}`, clientArg.ip, usedIdsArg, undefined, connected));
    }
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} RX Rate`, deviceId, `unifi_client_rx_${this.slug(mac)}`, this.clientRx(clientArg), usedIdsArg, 'MB/s', connected);
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} TX Rate`, deviceId, `unifi_client_tx_${this.slug(mac)}`, this.clientTx(clientArg), usedIdsArg, 'MB/s', connected);
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Wired Link Speed`, deviceId, `unifi_client_wired_speed_${this.slug(mac)}`, this.numberValue(clientArg.wiredRateMbps, clientArg.wired_rate_mbps), usedIdsArg, 'Mbit/s', connected && this.clientWired(clientArg));
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} RSSI`, deviceId, `unifi_client_rssi_${this.slug(mac)}`, this.numberValue(clientArg.rssi), usedIdsArg, 'dBm', connected && !this.clientWired(clientArg));
  }

  private static pushDeviceEntities(entitiesArg: IIntegrationEntity[], deviceArg: IUnifiDevice, snapshotArg: IUnifiSnapshot, usedIdsArg: Map<string, number>): void {
    const name = this.deviceName(deviceArg);
    const deviceId = this.deviceId(deviceArg);
    const mac = this.normalizeMac(deviceArg.mac) || deviceArg.mac;
    const connected = this.deviceConnected(deviceArg);
    entitiesArg.push(this.entity('binary_sensor', `${name} Connected`, deviceId, `unifi_device_connected_${this.slug(mac)}`, connected ? 'on' : 'off', usedIdsArg, {
      deviceClass: 'connectivity',
      mac,
      ip: deviceArg.ip,
    }, true));
    entitiesArg.push(this.entity('sensor', `${name} State`, deviceId, `unifi_device_state_${this.slug(mac)}`, this.deviceState(deviceArg), usedIdsArg, undefined, true));
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Clients`, deviceId, `unifi_device_clients_${this.slug(mac)}`, this.clientsForDevice(snapshotArg, deviceArg), usedIdsArg, undefined, connected);
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Uptime`, deviceId, `unifi_device_uptime_${this.slug(mac)}`, this.numberValue(deviceArg.uptime), usedIdsArg, 's', connected);
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Temperature`, deviceId, `unifi_device_temperature_${this.slug(mac)}`, this.numberValue(deviceArg.generalTemperature, deviceArg.general_temperature), usedIdsArg, 'C', connected);
    const stats = deviceArg.systemStats || deviceArg['system-stats'];
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} CPU Utilization`, deviceId, `unifi_device_cpu_${this.slug(mac)}`, this.numberValue(stats?.cpu), usedIdsArg, '%', connected);
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Memory Utilization`, deviceId, `unifi_device_memory_${this.slug(mac)}`, this.numberValue(stats?.mem), usedIdsArg, '%', connected);
  }

  private static pushWlanEntities(entitiesArg: IIntegrationEntity[], wlanArg: IUnifiWlan, snapshotArg: IUnifiSnapshot, usedIdsArg: Map<string, number>): void {
    const name = wlanArg.name;
    const wlanId = this.wlanId(wlanArg);
    const deviceId = this.wlanDeviceId(wlanArg);
    const enabled = this.booleanValue(wlanArg.enabled) !== false;
    entitiesArg.push(this.entity('switch', name, deviceId, `unifi_wlan_${this.slug(wlanId)}`, enabled ? 'on' : 'off', usedIdsArg, {
      nativeType: 'wlan',
      wlanId,
      security: wlanArg.security,
      hidden: this.booleanValue(wlanArg.hideSsid, wlanArg.hide_ssid),
      guest: this.booleanValue(wlanArg.isGuest, wlanArg.is_guest),
      writable: true,
    }, true));
    this.pushNumericEntity(entitiesArg, 'sensor', `${name} Clients`, deviceId, `unifi_wlan_clients_${this.slug(wlanId)}`, this.clientsForWlan(snapshotArg, wlanArg), usedIdsArg, undefined, enabled);
  }

  private static pushPortEntities(entitiesArg: IIntegrationEntity[], portArg: IUnifiPort, snapshotArg: IUnifiSnapshot, usedIdsArg: Map<string, number>): void {
    const device = snapshotArg.devices.find((deviceArg) => this.normalizeMac(deviceArg.mac) === this.normalizeMac(this.portDeviceMac(portArg)));
    const parentDeviceId = device ? this.deviceId(device) : `unifi.device.${this.slug(this.portDeviceMac(portArg) || 'unknown')}`;
    const parentName = device ? this.deviceName(device) : 'UniFi Device';
    const portName = this.portName(portArg);
    const baseName = `${parentName} ${portName}`;
    const uniqueBase = `${this.slug(this.portDeviceMac(portArg) || 'unknown')}_${this.slug(String(this.portIdx(portArg) || portArg.ifname || portName))}`;
    const available = device ? this.deviceConnected(device) : true;
    entitiesArg.push(this.entity('binary_sensor', `${baseName} Link`, parentDeviceId, `unifi_port_link_${uniqueBase}`, portArg.up ? 'on' : 'off', usedIdsArg, {
      deviceClass: 'connectivity',
      deviceMac: this.portDeviceMac(portArg),
      portIdx: this.portIdx(portArg),
    }, available));
    if (this.portHasPoe(portArg)) {
      entitiesArg.push(this.entity('switch', `${baseName} PoE`, parentDeviceId, `unifi_port_poe_${uniqueBase}`, this.portPoeEnabled(portArg) ? 'on' : 'off', usedIdsArg, {
        nativeType: 'poe_port',
        deviceMac: this.portDeviceMac(portArg),
        portIdx: this.portIdx(portArg),
        poeMode: portArg.poeMode || portArg.poe_mode,
        writable: true,
      }, available));
      this.pushNumericEntity(entitiesArg, 'sensor', `${baseName} PoE Power`, parentDeviceId, `unifi_port_poe_power_${uniqueBase}`, this.numberValue(portArg.poePower, portArg.poe_power), usedIdsArg, 'W', available);
    }
    if (typeof this.booleanValue(portArg.enabled, portArg.enable) === 'boolean') {
      entitiesArg.push(this.entity('switch', `${baseName} Enabled`, parentDeviceId, `unifi_port_enabled_${uniqueBase}`, this.booleanValue(portArg.enabled, portArg.enable) ? 'on' : 'off', usedIdsArg, {
        nativeType: 'port_enabled',
        deviceMac: this.portDeviceMac(portArg),
        portIdx: this.portIdx(portArg),
      }, available));
    }
    this.pushNumericEntity(entitiesArg, 'sensor', `${baseName} Link Speed`, parentDeviceId, `unifi_port_speed_${uniqueBase}`, this.numberValue(portArg.speed), usedIdsArg, 'Mbit/s', available);
    this.pushNumericEntity(entitiesArg, 'sensor', `${baseName} RX Rate`, parentDeviceId, `unifi_port_rx_${uniqueBase}`, this.numberValue(portArg.rxBytesR, portArg['rx_bytes-r']), usedIdsArg, 'B/s', available);
    this.pushNumericEntity(entitiesArg, 'sensor', `${baseName} TX Rate`, parentDeviceId, `unifi_port_tx_${uniqueBase}`, this.numberValue(portArg.txBytesR, portArg['tx_bytes-r']), usedIdsArg, 'B/s', available);
  }

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

  private static pushNumericEntity(entitiesArg: IIntegrationEntity[], platformArg: TEntityPlatform, nameArg: string, deviceIdArg: string, uniqueIdArg: string, valueArg: number | undefined, usedIdsArg: Map<string, number>, unitArg?: string, availableArg = true): void {
    if (typeof valueArg !== 'number' || Number.isNaN(valueArg)) {
      return;
    }
    entitiesArg.push(this.entity(platformArg, nameArg, deviceIdArg, uniqueIdArg, valueArg, usedIdsArg, unitArg ? { unit: unitArg } : undefined, availableArg));
  }

  private static withDerivedPorts(snapshotArg: IUnifiSnapshot): IUnifiPort[] {
    const ports = [...snapshotArg.ports];
    const seen = new Set(ports.map((portArg) => this.portId(portArg)));
    for (const device of snapshotArg.devices) {
      for (const port of device.portTable || device.port_table || []) {
        const withDevice = { ...port, deviceMac: port.deviceMac || port.device_mac || device.mac };
        const id = this.portId(withDevice);
        if (!seen.has(id)) {
          seen.add(id);
          ports.push(withDevice);
        }
      }
    }
    return ports;
  }

  private static portsForDevice(snapshotArg: IUnifiSnapshot, deviceArg: IUnifiDevice): IUnifiPort[] {
    const mac = this.normalizeMac(deviceArg.mac);
    return this.withDerivedPorts(snapshotArg).filter((portArg) => this.normalizeMac(this.portDeviceMac(portArg)) === mac);
  }

  private static portId(portArg: IUnifiPort): string {
    return `${this.normalizeMac(this.portDeviceMac(portArg)) || 'unknown'}_${this.portIdx(portArg) || portArg.ifname || portArg.name || 'port'}`;
  }

  private static portDeviceMac(portArg: IUnifiPort): string | undefined {
    return portArg.deviceMac || portArg.device_mac;
  }

  private static portIdx(portArg: IUnifiPort): number | string | undefined {
    return portArg.portIdx ?? portArg.port_idx ?? portArg.ifname;
  }

  private static portKey(portArg: IUnifiPort): string {
    return this.slug(String(this.portIdx(portArg) || portArg.name || 'port'));
  }

  private static portName(portArg: IUnifiPort): string {
    const idx = this.portIdx(portArg);
    if (portArg.name && portArg.name.trim()) {
      return portArg.name;
    }
    return idx ? `Port ${idx}` : 'Port';
  }

  private static portHasPoe(portArg: IUnifiPort): boolean {
    return this.booleanValue(portArg.portPoe, portArg.port_poe, portArg.poeEnable, portArg.poe_enable) === true || (this.numberValue(portArg.poeCaps, portArg.poe_caps) ?? 0) > 0;
  }

  private static portPoeEnabled(portArg: IUnifiPort): boolean {
    const mode = String(portArg.poeMode || portArg.poe_mode || '').toLowerCase();
    if (mode) {
      return mode !== 'off';
    }
    return this.booleanValue(portArg.poeEnable, portArg.poe_enable, portArg.portPoe, portArg.port_poe) === true;
  }

  private static deviceId(deviceArg: IUnifiDevice): string {
    return `unifi.device.${this.slug(this.normalizeMac(deviceArg.mac) || deviceArg.deviceId || deviceArg.device_id || deviceArg.id || 'unknown')}`;
  }

  private static clientDeviceId(clientArg: IUnifiClient): string {
    return `unifi.client.${this.slug(this.normalizeMac(clientArg.mac) || clientArg.mac)}`;
  }

  private static wlanDeviceId(wlanArg: IUnifiWlan): string {
    return `unifi.wlan.${this.slug(this.wlanId(wlanArg))}`;
  }

  private static wlanId(wlanArg: IUnifiWlan): string {
    return wlanArg.id || wlanArg._id || wlanArg.name;
  }

  private static deviceName(deviceArg: IUnifiDevice): string {
    return deviceArg.name || deviceArg.model || this.normalizeMac(deviceArg.mac) || 'UniFi Device';
  }

  private static clientName(clientArg: IUnifiClient): string {
    return clientArg.name || clientArg.hostname || clientArg.deviceName || clientArg.device_name || this.normalizeMac(clientArg.mac) || 'UniFi Client';
  }

  private static deviceConnected(deviceArg: IUnifiDevice): boolean {
    if (deviceArg.disabled) {
      return false;
    }
    if (typeof deviceArg.state === 'number') {
      return deviceArg.state === connectedDeviceState;
    }
    if (typeof deviceArg.state === 'string') {
      return ['connected', 'online', '1'].includes(deviceArg.state.toLowerCase());
    }
    return true;
  }

  private static clientConnected(clientArg: IUnifiClient): boolean {
    const lastSeen = this.numberValue(clientArg.lastSeen, clientArg.last_seen);
    if (lastSeen && Date.now() / 1000 - lastSeen > 3600) {
      return false;
    }
    return true;
  }

  private static clientWired(clientArg: IUnifiClient): boolean {
    return this.booleanValue(clientArg.isWired, clientArg.is_wired) === true;
  }

  private static deviceState(deviceArg: IUnifiDevice): string {
    const state = deviceArg.state;
    if (state === 0) return 'disconnected';
    if (state === 1) return 'connected';
    if (state === 2) return 'pending';
    if (state === 3) return 'firmware_mismatch';
    if (state === 4) return 'upgrading';
    if (state === 5) return 'provisioning';
    if (state === 6) return 'heartbeat_missed';
    if (state === 7) return 'adopting';
    if (state === 8) return 'deleting';
    if (state === 9) return 'inform_error';
    if (state === 10) return 'adoption_failed';
    if (state === 11) return 'isolated';
    return typeof state === 'string' ? state : 'unknown';
  }

  private static clientsForWlan(snapshotArg: IUnifiSnapshot, wlanArg: IUnifiWlan): number {
    return snapshotArg.clients.filter((clientArg) => clientArg.essid === wlanArg.name && this.clientConnected(clientArg)).length;
  }

  private static clientsForDevice(snapshotArg: IUnifiSnapshot, deviceArg: IUnifiDevice): number {
    const mac = this.normalizeMac(deviceArg.mac);
    return snapshotArg.clients.filter((clientArg) => {
      const apMac = this.normalizeMac(clientArg.apMac || clientArg.ap_mac);
      const switchMac = this.normalizeMac(clientArg.switchMac || clientArg.sw_mac);
      return (apMac === mac || switchMac === mac) && this.clientConnected(clientArg);
    }).length;
  }

  private static clientRx(clientArg: IUnifiClient): number | undefined {
    const value = this.clientWired(clientArg)
      ? this.numberValue(clientArg.wiredRxBytesR, clientArg['wired-rx_bytes-r'])
      : this.numberValue(clientArg.rxBytesR, clientArg['rx_bytes-r']);
    return value === undefined ? undefined : value / 1000000;
  }

  private static clientTx(clientArg: IUnifiClient): number | undefined {
    const value = this.clientWired(clientArg)
      ? this.numberValue(clientArg.wiredTxBytesR, clientArg['wired-tx_bytes-r'])
      : this.numberValue(clientArg.txBytesR, clientArg['tx_bytes-r']);
    return value === undefined ? undefined : value / 1000000;
  }

  private static findTargetEntity(snapshotArg: IUnifiSnapshot, 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 macFromTarget(snapshotArg: IUnifiSnapshot, requestArg: IServiceCallRequest): string | undefined {
    const target = this.findTargetEntity(snapshotArg, requestArg);
    return this.stringValue(target?.attributes?.mac);
  }

  private static manualItems<TKey extends 'sites' | 'clients' | 'wlans'>(configArg: IUnifiConfig, keyArg: TKey): NonNullable<IUnifiConfig[TKey]> {
    return (configArg.manualEntries || []).flatMap((entryArg) => entryArg.snapshot?.[keyArg] || entryArg[keyArg] || []) as NonNullable<IUnifiConfig[TKey]>;
  }

  private static booleanValue(...valuesArg: unknown[]): boolean | undefined {
    for (const value of valuesArg) {
      if (typeof value === 'boolean') {
        return value;
      }
      if (typeof value === 'string') {
        if (['true', '1', 'yes', 'on'].includes(value.toLowerCase())) return true;
        if (['false', '0', 'no', 'off'].includes(value.toLowerCase())) return false;
      }
    }
    return undefined;
  }

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

  private static stringValue(valueArg: unknown): string | undefined {
    if (typeof valueArg === 'string' && valueArg) {
      return valueArg;
    }
    if (typeof valueArg === 'number') {
      return String(valueArg);
    }
    return undefined;
  }

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