import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IIntegrationEvent, IServiceCallRequest } from '../../core/types.js';
import { airosAttribution, airosDefaultHttpPort, airosDefaultHttpsPort, airosDefaultName, airosDefaultSsl, airosDefaultVerifySsl, airosDefaultUsername, airosDomain, airosManufacturer } from './airos.constants.js';
import type { IAirosCommand, IAirosConfig, IAirosDerivedSnapshot, IAirosEvent, IAirosFirmwareStatus, IAirosRawInterface, IAirosRawStatus, IAirosSnapshot, IAirosValueMap, TAirosWirelessMode, TAirosWirelessRole } from './airos.types.js';

export class AirosMapper {
  public static toSnapshot(configArg: IAirosConfig = {}, overridesArg: Partial<IAirosSnapshot> = {}, eventsArg: IAirosEvent[] = []): IAirosSnapshot {
    const source = configArg.snapshot;
    const rawStatus = overridesArg.rawStatus || configArg.rawStatus || source?.rawStatus;
    const firmware = overridesArg.firmware || configArg.firmwareStatus || source?.firmware;
    const hostData = this.objectValue(rawStatus?.host);
    const servicesData = this.objectValue(rawStatus?.services);
    const wirelessData = this.objectValue(rawStatus?.wireless);
    const derived = this.derive(rawStatus, configArg, source?.derived);
    const ssl = overridesArg.device?.ssl ?? this.sslValue(configArg, source?.device.ssl);
    const port = overridesArg.device?.port || configArg.port || source?.device.port || (ssl ? airosDefaultHttpsPort : airosDefaultHttpPort);
    const host = configArg.host || configArg.ipAddress || configArg.address || configArg.ip || source?.device.host;
    const fwVersion = this.stringValue(overridesArg.device?.firmwareVersion) || this.stringValue(hostData?.fwversion) || source?.device.firmwareVersion;
    const fwMajor = overridesArg.device?.firmwareMajor ?? derived.fwMajor ?? source?.device.firmwareMajor;
    const name = overridesArg.device?.name || configArg.name || source?.device.name || this.stringValue(hostData?.hostname) || airosDefaultName;
    const rawPresent = Boolean(rawStatus);
    const connected = overridesArg.connected ?? configArg.connected ?? source?.connected ?? rawPresent;
    const sourceName = overridesArg.source || source?.source || (rawPresent ? 'manual' : 'runtime');
    const updatedAt = overridesArg.updatedAt || source?.updatedAt || new Date().toISOString();

    return {
      connected,
      source: sourceName,
      device: {
        id: overridesArg.device?.id || configArg.id || source?.device.id || derived.mac || host || name,
        name,
        host,
        port,
        ssl,
        verifySsl: overridesArg.device?.verifySsl ?? this.verifySslValue(configArg, source?.device.verifySsl),
        configurationUrl: host ? `${ssl ? 'https' : 'http'}://${host}${this.defaultPort(ssl) === port ? '' : `:${port}`}` : undefined,
        macAddress: overridesArg.device?.macAddress || configArg.macAddress || configArg.mac || source?.device.macAddress || derived.mac,
        manufacturer: overridesArg.device?.manufacturer || configArg.manufacturer || source?.device.manufacturer || airosManufacturer,
        modelName: overridesArg.device?.modelName || configArg.modelName || configArg.model || source?.device.modelName || this.stringValue(hostData?.devmodel) || airosDefaultName,
        modelId: overridesArg.device?.modelId || source?.device.modelId || derived.sku,
        firmwareVersion: fwVersion,
        firmwareMajor: fwMajor,
        authenticated: overridesArg.device?.authenticated ?? source?.device.authenticated,
        available: overridesArg.device?.available ?? source?.device.available ?? connected,
        metadata: this.cleanAttributes({
          ...source?.device.metadata,
          ...configArg.metadata,
          ...overridesArg.device?.metadata,
          username: configArg.username || airosDefaultUsername,
          macInterface: derived.macInterface,
        }),
      },
      host: {
        hostname: overridesArg.host?.hostname || this.stringValue(hostData?.hostname) || source?.host.hostname || name,
        uptime: this.numberValue(overridesArg.host?.uptime) ?? this.numberValue(hostData?.uptime) ?? source?.host.uptime,
        cpuLoad: this.numberValue(overridesArg.host?.cpuLoad) ?? this.numberValue(hostData?.cpuload) ?? source?.host.cpuLoad ?? null,
        netRole: overridesArg.host?.netRole || this.stringValue(hostData?.netrole) || source?.host.netRole,
        temperature: this.numberValue(overridesArg.host?.temperature) ?? this.numberValue(hostData?.temperature) ?? source?.host.temperature ?? null,
        totalRam: this.numberValue(overridesArg.host?.totalRam) ?? this.numberValue(hostData?.totalram) ?? source?.host.totalRam,
        freeRam: this.numberValue(overridesArg.host?.freeRam) ?? this.numberValue(hostData?.freeram) ?? source?.host.freeRam,
        attributes: this.cleanAttributes({ ...source?.host.attributes, ...overridesArg.host?.attributes }),
      },
      services: {
        dhcpClient: this.booleanValue(overridesArg.services?.dhcpClient) ?? this.booleanValue(servicesData?.dhcpc) ?? source?.services.dhcpClient,
        dhcpServer: this.booleanValue(overridesArg.services?.dhcpServer) ?? this.booleanValue(servicesData?.dhcpd) ?? source?.services.dhcpServer,
        dhcp6Server: this.booleanValue(overridesArg.services?.dhcp6Server) ?? this.booleanValue(servicesData?.dhcp6d_stateful) ?? source?.services.dhcp6Server,
        pppoe: this.booleanValue(overridesArg.services?.pppoe) ?? this.booleanValue(servicesData?.pppoe) ?? source?.services.pppoe,
        portForwarding: this.booleanValue(overridesArg.services?.portForwarding) ?? this.booleanValue(rawStatus?.portfw) ?? source?.services.portForwarding,
        attributes: this.cleanAttributes({ ...source?.services.attributes, ...overridesArg.services?.attributes }),
      },
      wireless: {
        essid: overridesArg.wireless?.essid || this.stringValue(wirelessData?.essid) || source?.wireless.essid,
        frequency: this.numberValue(overridesArg.wireless?.frequency) ?? this.numberValue(wirelessData?.frequency) ?? source?.wireless.frequency,
        distance: this.numberValue(overridesArg.wireless?.distance) ?? this.numberValue(wirelessData?.distance) ?? source?.wireless.distance,
        antennaGain: this.numberValue(overridesArg.wireless?.antennaGain) ?? this.numberValue(wirelessData?.antenna_gain) ?? source?.wireless.antennaGain ?? null,
        mode: overridesArg.wireless?.mode || derived.mode || source?.wireless.mode || 'unknown',
        role: overridesArg.wireless?.role || derived.role || source?.wireless.role || 'unknown',
        rawMode: overridesArg.wireless?.rawMode || this.stringValue(wirelessData?.mode) || source?.wireless.rawMode,
        pollingDownloadCapacity: this.numberValue(overridesArg.wireless?.pollingDownloadCapacity) ?? this.numberValue(this.objectValue(wirelessData?.polling)?.dl_capacity) ?? source?.wireless.pollingDownloadCapacity ?? null,
        pollingUploadCapacity: this.numberValue(overridesArg.wireless?.pollingUploadCapacity) ?? this.numberValue(this.objectValue(wirelessData?.polling)?.ul_capacity) ?? source?.wireless.pollingUploadCapacity ?? null,
        throughputTx: this.numberValue(overridesArg.wireless?.throughputTx) ?? this.numberValue(this.objectValue(wirelessData?.throughput)?.tx) ?? source?.wireless.throughputTx ?? null,
        throughputRx: this.numberValue(overridesArg.wireless?.throughputRx) ?? this.numberValue(this.objectValue(wirelessData?.throughput)?.rx) ?? source?.wireless.throughputRx ?? null,
        attributes: this.cleanAttributes({ ...source?.wireless.attributes, ...overridesArg.wireless?.attributes }),
      },
      firmware,
      derived,
      rawStatus,
      updatedAt,
      events: [...(source?.events || []), ...eventsArg, ...(overridesArg.events || [])],
      metadata: this.cleanAttributes({
        ...source?.metadata,
        ...configArg.metadata,
        ...overridesArg.metadata,
        nativeHttpImplemented: true,
        nativeHttpEnabled: configArg.nativeHttpEnabled !== false,
        commandExecutorConfigured: Boolean(configArg.commandExecutor || configArg.transport?.execute),
        nativeClientConfigured: Boolean(configArg.nativeClient),
      }),
      error: overridesArg.error || source?.error,
    };
  }

  public static mergeSnapshot(baseArg: IAirosSnapshot, patchArg: Partial<IAirosSnapshot>): IAirosSnapshot {
    return {
      ...baseArg,
      ...patchArg,
      device: { ...baseArg.device, ...patchArg.device, metadata: this.cleanAttributes({ ...baseArg.device.metadata, ...patchArg.device?.metadata }) },
      host: { ...baseArg.host, ...patchArg.host, attributes: this.cleanAttributes({ ...baseArg.host.attributes, ...patchArg.host?.attributes }) },
      services: { ...baseArg.services, ...patchArg.services, attributes: this.cleanAttributes({ ...baseArg.services.attributes, ...patchArg.services?.attributes }) },
      wireless: { ...baseArg.wireless, ...patchArg.wireless, attributes: this.cleanAttributes({ ...baseArg.wireless.attributes, ...patchArg.wireless?.attributes }) },
      derived: { ...baseArg.derived, ...patchArg.derived },
      events: [...baseArg.events, ...(patchArg.events || [])],
      metadata: this.cleanAttributes({ ...baseArg.metadata, ...patchArg.metadata }),
      updatedAt: patchArg.updatedAt || baseArg.updatedAt || new Date().toISOString(),
    };
  }

  public static toDevices(snapshotArg: IAirosSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'cpu_load', capability: 'sensor', name: 'CPU load', readable: true, writable: false, unit: '%' },
      { id: 'uptime', capability: 'sensor', name: 'Uptime', readable: true, writable: false, unit: 's' },
      { id: 'wireless_frequency', capability: 'sensor', name: 'Wireless frequency', readable: true, writable: false, unit: 'MHz' },
      { id: 'wireless_distance', capability: 'sensor', name: 'Wireless distance', readable: true, writable: false, unit: 'm' },
      { id: 'download_capacity', capability: 'sensor', name: 'Download capacity', readable: true, writable: false, unit: 'kbit/s' },
      { id: 'upload_capacity', capability: 'sensor', name: 'Upload capacity', readable: true, writable: false, unit: 'kbit/s' },
      { id: 'dhcp_client', capability: 'sensor', name: 'DHCP client', readable: true, writable: false },
      { id: 'dhcp_server', capability: 'sensor', name: 'DHCP server', readable: true, writable: false },
      { id: 'pppoe', capability: 'sensor', name: 'PPPoE link', readable: true, writable: false },
      { id: 'reboot', capability: 'switch', name: 'Reboot', readable: false, writable: true },
    ];
    if ((snapshotArg.device.firmwareMajor || 0) >= 8) {
      features.push(
        { id: 'throughput_tx', capability: 'sensor', name: 'Throughput transmit', readable: true, writable: false, unit: 'kbit/s' },
        { id: 'throughput_rx', capability: 'sensor', name: 'Throughput receive', readable: true, writable: false, unit: 'kbit/s' },
        { id: 'firmware_update', capability: 'switch', name: 'Firmware update', readable: true, writable: true },
      );
    }

    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'cpu_load', value: snapshotArg.host.cpuLoad ?? null, updatedAt },
      { featureId: 'uptime', value: snapshotArg.host.uptime ?? null, updatedAt },
      { featureId: 'wireless_frequency', value: snapshotArg.wireless.frequency ?? null, updatedAt },
      { featureId: 'wireless_distance', value: snapshotArg.wireless.distance ?? null, updatedAt },
      { featureId: 'download_capacity', value: snapshotArg.wireless.pollingDownloadCapacity ?? null, updatedAt },
      { featureId: 'upload_capacity', value: snapshotArg.wireless.pollingUploadCapacity ?? null, updatedAt },
      { featureId: 'dhcp_client', value: snapshotArg.services.dhcpClient ?? null, updatedAt },
      { featureId: 'dhcp_server', value: snapshotArg.services.dhcpServer ?? null, updatedAt },
      { featureId: 'pppoe', value: snapshotArg.services.pppoe ?? null, updatedAt },
    ];
    if ((snapshotArg.device.firmwareMajor || 0) >= 8) {
      state.push(
        { featureId: 'throughput_tx', value: snapshotArg.wireless.throughputTx ?? null, updatedAt },
        { featureId: 'throughput_rx', value: snapshotArg.wireless.throughputRx ?? null, updatedAt },
        { featureId: 'firmware_update', value: snapshotArg.firmware?.update ?? false, updatedAt },
      );
    }

    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: airosDomain,
      name: snapshotArg.device.name || airosDefaultName,
      protocol: 'http',
      manufacturer: snapshotArg.device.manufacturer || airosManufacturer,
      model: snapshotArg.device.modelName || airosDefaultName,
      online: snapshotArg.connected && snapshotArg.device.available !== false,
      features,
      state,
      metadata: this.cleanAttributes({
        attribution: airosAttribution,
        host: snapshotArg.device.host,
        port: snapshotArg.device.port,
        ssl: snapshotArg.device.ssl,
        verifySsl: snapshotArg.device.verifySsl,
        configurationUrl: snapshotArg.device.configurationUrl,
        macAddress: snapshotArg.device.macAddress,
        firmwareVersion: snapshotArg.device.firmwareVersion,
        firmwareMajor: snapshotArg.device.firmwareMajor,
        modelId: snapshotArg.device.modelId,
        source: snapshotArg.source,
        error: snapshotArg.error,
        ...snapshotArg.metadata,
      }),
    }];
  }

  public static toEntities(snapshotArg: IAirosSnapshot): IIntegrationEntity[] {
    const entities: IIntegrationEntity[] = [
      this.sensorEntity(snapshotArg, 'host_cpuload', 'CPU load', snapshotArg.host.cpuLoad ?? null, { unit_of_measurement: '%', nativeType: 'host_cpuload' }),
      this.sensorEntity(snapshotArg, 'host_netrole', 'Network role', snapshotArg.host.netRole ?? null, { nativeType: 'host_netrole' }),
      this.sensorEntity(snapshotArg, 'wireless_frequency', 'Wireless frequency', snapshotArg.wireless.frequency ?? null, { unit_of_measurement: 'MHz', nativeType: 'wireless_frequency' }),
      this.sensorEntity(snapshotArg, 'wireless_essid', 'Wireless SSID', snapshotArg.wireless.essid ?? null, { nativeType: 'wireless_essid' }),
      this.sensorEntity(snapshotArg, 'host_uptime', 'Uptime', snapshotArg.host.uptime ?? null, { unit_of_measurement: 's', nativeType: 'host_uptime' }),
      this.sensorEntity(snapshotArg, 'wireless_distance', 'Wireless distance', snapshotArg.wireless.distance ?? null, { unit_of_measurement: 'm', nativeType: 'wireless_distance' }),
      this.sensorEntity(snapshotArg, 'wireless_mode', 'Wireless mode', snapshotArg.wireless.mode ?? null, { nativeType: 'wireless_mode' }),
      this.sensorEntity(snapshotArg, 'wireless_role', 'Wireless role', snapshotArg.wireless.role ?? null, { nativeType: 'wireless_role' }),
      this.sensorEntity(snapshotArg, 'wireless_antenna_gain', 'Antenna gain', snapshotArg.wireless.antennaGain ?? null, { unit_of_measurement: 'dB', nativeType: 'wireless_antenna_gain' }),
      this.sensorEntity(snapshotArg, 'wireless_polling_dl_capacity', 'Download capacity', snapshotArg.wireless.pollingDownloadCapacity ?? null, { unit_of_measurement: 'kbit/s', nativeType: 'wireless_polling_dl_capacity' }),
      this.sensorEntity(snapshotArg, 'wireless_polling_ul_capacity', 'Upload capacity', snapshotArg.wireless.pollingUploadCapacity ?? null, { unit_of_measurement: 'kbit/s', nativeType: 'wireless_polling_ul_capacity' }),
      this.binarySensorEntity(snapshotArg, 'dhcp_client', 'DHCP client', snapshotArg.services.dhcpClient),
      this.binarySensorEntity(snapshotArg, 'dhcp_server', 'DHCP server', snapshotArg.services.dhcpServer),
      this.binarySensorEntity(snapshotArg, 'pppoe', 'PPPoE link', snapshotArg.services.pppoe),
      this.rebootButtonEntity(snapshotArg),
    ];

    if ((snapshotArg.device.firmwareMajor || 0) >= 8) {
      entities.push(
        this.sensorEntity(snapshotArg, 'wireless_throughput_tx', 'Throughput transmit (actual)', snapshotArg.wireless.throughputTx ?? null, { unit_of_measurement: 'kbit/s', nativeType: 'wireless_throughput_tx' }),
        this.sensorEntity(snapshotArg, 'wireless_throughput_rx', 'Throughput receive (actual)', snapshotArg.wireless.throughputRx ?? null, { unit_of_measurement: 'kbit/s', nativeType: 'wireless_throughput_rx' }),
        this.binarySensorEntity(snapshotArg, 'portfw', 'Port forwarding', snapshotArg.services.portForwarding),
        this.binarySensorEntity(snapshotArg, 'dhcp6_server', 'DHCPv6 server', snapshotArg.services.dhcp6Server),
        this.updateEntity(snapshotArg),
      );
    }

    return entities;
  }

  public static commandForService(snapshotArg: IAirosSnapshot, requestArg: IServiceCallRequest): IAirosCommand | undefined {
    const target = requestArg.target || {};
    const deviceId = this.deviceId(snapshotArg);
    const buttonId = this.rebootButtonEntityId(snapshotArg);
    const updateId = this.updateEntityId(snapshotArg);
    const targetMatchesDevice = !target.deviceId || target.deviceId === deviceId;
    const noEntityTarget = !target.entityId;

    if (requestArg.domain === airosDomain && requestArg.service === 'firmware_update_check' && targetMatchesDevice) {
      return this.command(snapshotArg, requestArg, 'firmware_update_check', 'api/fw/update-check', noEntityTarget ? undefined : target.entityId);
    }
    if (requestArg.domain === airosDomain && requestArg.service === 'download_update' && targetMatchesDevice) {
      return this.command(snapshotArg, requestArg, 'download_update', 'api/fw/download', noEntityTarget ? undefined : target.entityId);
    }
    if ((requestArg.domain === airosDomain && requestArg.service === 'install_update' && targetMatchesDevice) || (requestArg.domain === 'update' && requestArg.service === 'install' && target.entityId === updateId)) {
      return this.command(snapshotArg, requestArg, 'install_update', 'fwflash.cgi', updateId);
    }
    if ((requestArg.domain === airosDomain && requestArg.service === 'reboot' && targetMatchesDevice) || (requestArg.domain === 'button' && requestArg.service === 'press' && target.entityId === buttonId)) {
      return this.command(snapshotArg, requestArg, 'reboot', 'reboot.cgi', buttonId);
    }
    return undefined;
  }

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

  public static deviceId(snapshotArg: IAirosSnapshot): string {
    return `airos.device.${this.slug(snapshotArg.device.id || snapshotArg.device.macAddress || snapshotArg.device.host || snapshotArg.device.name || 'device')}`;
  }

  public static rebootButtonEntityId(snapshotArg: IAirosSnapshot): string {
    return `button.${this.slug(snapshotArg.device.name || snapshotArg.device.id || 'airos_device')}_reboot`;
  }

  public static updateEntityId(snapshotArg: IAirosSnapshot): string {
    return `update.${this.slug(snapshotArg.device.name || snapshotArg.device.id || 'airos_device')}_firmware_update`;
  }

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

  public static numberValue(valueArg: unknown): number | undefined {
    if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg === 'string' && valueArg.trim()) {
      const parsed = Number(valueArg.replace(/\s*(MHz|dBi|dBm|kbps|kbit\/s|s)$/i, ''));
      return Number.isFinite(parsed) ? parsed : undefined;
    }
    return undefined;
  }

  public static slug(valueArg: unknown): string {
    const slug = String(valueArg || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
    return slug || 'airos';
  }

  public static cleanAttributes<TValue extends Record<string, unknown>>(valueArg: TValue): TValue {
    const result: Record<string, unknown> = {};
    for (const [key, value] of Object.entries(valueArg)) {
      if (value !== undefined) {
        result[key] = value;
      }
    }
    return result as TValue;
  }

  public static derive(rawStatusArg: IAirosRawStatus | undefined, configArg: IAirosConfig = {}, sourceArg?: IAirosDerivedSnapshot): IAirosDerivedSnapshot {
    const wireless = this.objectValue(rawStatusArg?.wireless);
    const rawDerived = (rawStatusArg?.derived || {}) as IAirosValueMap;
    const rawMode = this.stringValue(wireless?.mode);
    const derivedMode = this.deriveWireless(rawMode);
    const macInfo = this.getMac(rawStatusArg?.interfaces);
    const fwVersion = this.stringValue(rawStatusArg?.host?.fwversion);
    const fwMajor = this.fwMajor(fwVersion);
    return this.cleanAttributes({
      ...sourceArg,
      mac: this.normalizeMac(rawDerived?.mac) || this.normalizeMac(configArg.macAddress || configArg.mac) || sourceArg?.mac || macInfo.mac,
      macInterface: this.stringValue(rawDerived?.macInterface) || this.stringValue(rawDerived?.mac_interface) || sourceArg?.macInterface || macInfo.macInterface,
      fwMajor: fwMajor ?? this.numberValue(rawDerived?.fwMajor) ?? sourceArg?.fwMajor,
      sku: this.stringValue(rawDerived?.sku) || sourceArg?.sku,
      role: derivedMode.role || sourceArg?.role,
      mode: derivedMode.mode || sourceArg?.mode,
      station: derivedMode.station ?? sourceArg?.station,
      accessPoint: derivedMode.accessPoint ?? sourceArg?.accessPoint,
      ptp: derivedMode.ptp ?? sourceArg?.ptp,
      ptmp: derivedMode.ptmp ?? sourceArg?.ptmp,
    });
  }

  private static command(snapshotArg: IAirosSnapshot, requestArg: IServiceCallRequest, actionArg: IAirosCommand['action'], methodArg: IAirosCommand['method'], entityIdArg?: string): IAirosCommand {
    return {
      action: actionArg,
      method: methodArg,
      service: requestArg.service,
      target: requestArg.target,
      data: requestArg.data,
      deviceId: this.deviceId(snapshotArg),
      entityId: entityIdArg,
      host: snapshotArg.device.host,
      transmitted: false,
      metadata: this.cleanAttributes({ firmwareMajor: snapshotArg.device.firmwareMajor, firmwareVersion: snapshotArg.device.firmwareVersion }),
    };
  }

  private static sensorEntity(snapshotArg: IAirosSnapshot, keyArg: string, nameArg: string, stateArg: unknown, attributesArg: Record<string, unknown>): IIntegrationEntity {
    return {
      id: `sensor.${this.slug(snapshotArg.device.name || snapshotArg.device.id || 'airos_device')}_${keyArg}`,
      uniqueId: `airos_${this.slug(snapshotArg.device.id || snapshotArg.device.macAddress || snapshotArg.device.host || snapshotArg.device.name)}_${keyArg}`,
      integrationDomain: airosDomain,
      deviceId: this.deviceId(snapshotArg),
      platform: 'sensor',
      name: nameArg,
      state: stateArg,
      available: snapshotArg.connected && snapshotArg.device.available !== false && stateArg !== undefined,
      attributes: this.cleanAttributes({ attribution: airosAttribution, ...attributesArg }),
    };
  }

  private static binarySensorEntity(snapshotArg: IAirosSnapshot, keyArg: string, nameArg: string, stateArg: boolean | undefined): IIntegrationEntity {
    return {
      id: `binary_sensor.${this.slug(snapshotArg.device.name || snapshotArg.device.id || 'airos_device')}_${keyArg}`,
      uniqueId: `airos_${this.slug(snapshotArg.device.id || snapshotArg.device.macAddress || snapshotArg.device.host || snapshotArg.device.name)}_${keyArg}`,
      integrationDomain: airosDomain,
      deviceId: this.deviceId(snapshotArg),
      platform: 'binary_sensor',
      name: nameArg,
      state: stateArg ?? null,
      available: snapshotArg.connected && snapshotArg.device.available !== false && stateArg !== undefined,
      attributes: this.cleanAttributes({ attribution: airosAttribution, nativeType: keyArg }),
    };
  }

  private static rebootButtonEntity(snapshotArg: IAirosSnapshot): IIntegrationEntity {
    return {
      id: this.rebootButtonEntityId(snapshotArg),
      uniqueId: `airos_${this.slug(snapshotArg.device.id || snapshotArg.device.macAddress || snapshotArg.device.host || snapshotArg.device.name)}_reboot`,
      integrationDomain: airosDomain,
      deviceId: this.deviceId(snapshotArg),
      platform: 'button',
      name: 'Reboot',
      state: 'idle',
      available: snapshotArg.connected && snapshotArg.device.available !== false,
      attributes: this.cleanAttributes({ attribution: airosAttribution, nativeType: 'reboot', writable: true }),
    };
  }

  private static updateEntity(snapshotArg: IAirosSnapshot): IIntegrationEntity {
    return {
      id: this.updateEntityId(snapshotArg),
      uniqueId: `airos_${this.slug(snapshotArg.device.id || snapshotArg.device.macAddress || snapshotArg.device.host || snapshotArg.device.name)}_firmware_update`,
      integrationDomain: airosDomain,
      deviceId: this.deviceId(snapshotArg),
      platform: 'update',
      name: 'Firmware update',
      state: snapshotArg.firmware?.update ? 'on' : 'off',
      available: snapshotArg.connected && snapshotArg.device.available !== false,
      attributes: this.cleanAttributes({
        attribution: airosAttribution,
        nativeType: 'firmware_update',
        installed_version: snapshotArg.device.firmwareVersion,
        latest_version: snapshotArg.firmware?.update ? snapshotArg.firmware.version : snapshotArg.device.firmwareVersion,
        release_url: snapshotArg.firmware?.changelog,
        writable: true,
      }),
    };
  }

  private static getMac(interfacesArg: IAirosRawInterface[] | undefined): { mac?: string; macInterface?: string } {
    if (!interfacesArg?.length) {
      return {};
    }
    const addresses = new Map<string, string>();
    for (const item of interfacesArg) {
      const ifname = this.stringValue(item.ifname);
      const mac = this.normalizeMac(item.hwaddr);
      if (ifname && mac && item.enabled !== false) {
        addresses.set(ifname, mac);
      }
    }
    for (const preferred of ['br0', 'eth0', 'ath0']) {
      const mac = addresses.get(preferred);
      if (mac) {
        return { mac, macInterface: preferred };
      }
    }
    const first = interfacesArg.find((itemArg) => this.normalizeMac(itemArg.hwaddr));
    return { mac: this.normalizeMac(first?.hwaddr), macInterface: this.stringValue(first?.ifname) };
  }

  private static fwMajor(valueArg: string | undefined): number | undefined {
    if (!valueArg) {
      return undefined;
    }
    const parsed = Number(valueArg.replace(/^v/i, '').split('.', 1)[0]);
    return Number.isFinite(parsed) ? parsed : undefined;
  }

  private static deriveWireless(valueArg: string | undefined): { role?: TAirosWirelessRole; mode?: TAirosWirelessMode; station?: boolean; accessPoint?: boolean; ptp?: boolean; ptmp?: boolean } {
    switch ((valueArg || '').toLowerCase()) {
      case 'ap-ptmp':
        return { role: 'access_point', mode: 'point_to_multipoint', accessPoint: true, station: false, ptmp: true, ptp: false };
      case 'sta-ptmp':
        return { role: 'station', mode: 'point_to_multipoint', accessPoint: false, station: true, ptmp: true, ptp: false };
      case 'ap-ptp':
      case 'ap':
        return { role: 'access_point', mode: 'point_to_point', accessPoint: true, station: false, ptmp: false, ptp: true };
      case 'sta-ptp':
      case 'sta':
        return { role: 'station', mode: 'point_to_point', accessPoint: false, station: true, ptmp: false, ptp: true };
      default:
        return { role: 'unknown', mode: 'unknown' };
    }
  }

  private static sslValue(configArg: IAirosConfig, fallbackArg?: boolean): boolean {
    return configArg.ssl ?? configArg.useSsl ?? configArg.advanced_settings?.ssl ?? fallbackArg ?? airosDefaultSsl;
  }

  private static verifySslValue(configArg: IAirosConfig, fallbackArg?: boolean): boolean {
    return configArg.verifySsl ?? configArg.verify_ssl ?? configArg.advanced_settings?.verifySsl ?? configArg.advanced_settings?.verify_ssl ?? fallbackArg ?? airosDefaultVerifySsl;
  }

  private static defaultPort(sslArg: boolean): number {
    return sslArg ? airosDefaultHttpsPort : airosDefaultHttpPort;
  }

  private static objectValue(valueArg: unknown): IAirosValueMap | undefined {
    return valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg) ? valueArg as IAirosValueMap : undefined;
  }

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

  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 normalized = valueArg.trim().toLowerCase();
      if (['true', 'yes', '1', 'on', 'enabled'].includes(normalized)) {
        return true;
      }
      if (['false', 'no', '0', 'off', 'disabled'].includes(normalized)) {
        return false;
      }
    }
    return undefined;
  }
}
