import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
import type {
  IElgatoBatteryInfo,
  IElgatoBatterySnapshot,
  IElgatoCommandRequest,
  IElgatoConfig,
  IElgatoDeviceSnapshotInfo,
  IElgatoInfo,
  IElgatoLightSnapshot,
  IElgatoRawData,
  IElgatoSettings,
  IElgatoSnapshot,
  IElgatoState,
  TElgatoColorMode,
  TElgatoSnapshotSource,
} from './elgato.types.js';
import { elgatoDefaultPort, elgatoDisplayName, elgatoDomain, elgatoManufacturer } from './elgato.types.js';

interface IElgatoSnapshotOptions {
  config: IElgatoConfig;
  rawData?: Partial<IElgatoRawData>;
  online?: boolean;
  source?: TElgatoSnapshotSource;
  error?: string;
}

interface IElgatoEntityDefinition {
  key: string;
  platform: TEntityPlatform;
  name: string;
  state: unknown;
  available: boolean;
  attributes?: Record<string, unknown>;
}

const batterySensorDefinitions: Array<{
  key: string;
  name: string;
  value: (batteryArg: IElgatoBatterySnapshot) => unknown;
  unit?: string;
  deviceClass?: string;
  stateClass?: string;
}> = [
  { key: 'battery', name: 'Battery', value: (batteryArg) => batteryArg.level, unit: '%', deviceClass: 'battery', stateClass: 'measurement' },
  { key: 'voltage', name: 'Voltage', value: (batteryArg) => batteryArg.voltage, unit: 'mV', deviceClass: 'voltage', stateClass: 'measurement' },
  { key: 'input_charge_current', name: 'Input Charge Current', value: (batteryArg) => batteryArg.inputChargeCurrent, unit: 'mA', deviceClass: 'current', stateClass: 'measurement' },
  { key: 'charge_power', name: 'Charge Power', value: (batteryArg) => batteryArg.chargePower, unit: 'W', deviceClass: 'power', stateClass: 'measurement' },
  { key: 'input_charge_voltage', name: 'Input Charge Voltage', value: (batteryArg) => batteryArg.inputChargeVoltage, unit: 'mV', deviceClass: 'voltage', stateClass: 'measurement' },
];

export class ElgatoMapper {
  public static toSnapshot(optionsArg: IElgatoSnapshotOptions): IElgatoSnapshot {
    if (optionsArg.config.snapshot && !optionsArg.rawData) {
      return this.normalizeSnapshot(this.clone(optionsArg.config.snapshot), optionsArg.config, optionsArg.source || 'snapshot');
    }

    const rawData = this.rawData(optionsArg.config, optionsArg.rawData);
    const online = optionsArg.online ?? optionsArg.config.online ?? this.hasRawData(rawData);
    const device = this.deviceInfo(optionsArg.config, rawData.info, online);
    const light = this.light(rawData.info, rawData.settings, rawData.state);
    const battery = this.battery(rawData.battery, rawData.settings);
    const capabilities = {
      localControl: this.hasCommandTransport(optionsArg.config, 'set_light'),
      colorTemperature: true,
      color: light.supportedColorModes.includes('hs'),
      identify: this.hasCommandTransport(optionsArg.config, 'identify'),
      restart: this.hasCommandTransport(optionsArg.config, 'restart'),
      battery: Boolean(battery),
      batterySettings: Boolean(rawData.settings?.battery),
    };

    return {
      device,
      light,
      battery,
      capabilities,
      rawData: this.hasRawData(rawData) ? rawData : undefined,
      online,
      updatedAt: rawData.fetchedAt || new Date().toISOString(),
      source: optionsArg.source || (this.hasRawData(rawData) ? 'manual' : 'runtime'),
      error: optionsArg.error,
    };
  }

  public static toDevices(snapshotArg: IElgatoSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'power', capability: 'light', name: 'Power', readable: true, writable: snapshotArg.capabilities.localControl },
      { id: 'brightness', capability: 'light', name: 'Brightness', readable: true, writable: snapshotArg.capabilities.localControl, unit: '%' },
      { id: 'color_temperature', capability: 'light', name: 'Color temperature', readable: true, writable: snapshotArg.capabilities.localControl, unit: 'K' },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'power', value: snapshotArg.light.on, updatedAt },
      { featureId: 'brightness', value: snapshotArg.light.brightness ?? null, updatedAt },
      { featureId: 'color_temperature', value: snapshotArg.light.colorTemperatureKelvin ?? null, updatedAt },
    ];

    if (snapshotArg.capabilities.color) {
      features.push({ id: 'hs_color', capability: 'light', name: 'HS color', readable: true, writable: snapshotArg.capabilities.localControl });
      state.push({ featureId: 'hs_color', value: { hue: snapshotArg.light.hue ?? null, saturation: snapshotArg.light.saturation ?? null }, updatedAt });
    }
    if (snapshotArg.battery) {
      features.push({ id: 'battery', capability: 'sensor', name: 'Battery', readable: true, writable: false, unit: '%' });
      state.push({ featureId: 'battery', value: snapshotArg.battery.level ?? null, updatedAt });
    }
    features.push({ id: 'identify', capability: 'switch', name: 'Identify', readable: false, writable: snapshotArg.capabilities.identify });
    features.push({ id: 'restart', capability: 'switch', name: 'Restart', readable: false, writable: snapshotArg.capabilities.restart });

    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: elgatoDomain,
      name: snapshotArg.device.name,
      protocol: snapshotArg.device.host ? 'http' : 'unknown',
      manufacturer: snapshotArg.device.manufacturer,
      model: snapshotArg.device.model || elgatoDisplayName,
      online: snapshotArg.online,
      features,
      state,
      metadata: this.cleanAttributes({
        serialNumber: snapshotArg.device.serialNumber,
        macAddress: snapshotArg.device.macAddress,
        firmwareVersion: snapshotArg.device.firmwareVersion,
        firmwareBuildNumber: snapshotArg.device.firmwareBuildNumber,
        hardwareBoardType: snapshotArg.device.hardwareBoardType,
        host: snapshotArg.device.host,
        port: snapshotArg.device.port,
        baseUrl: snapshotArg.device.baseUrl,
        source: snapshotArg.source,
        error: snapshotArg.error,
      }),
    }];
  }

  public static toEntities(snapshotArg: IElgatoSnapshot): IIntegrationEntity[] {
    const deviceId = this.deviceId(snapshotArg);
    const uniqueBase = this.uniqueBase(snapshotArg);
    const baseName = snapshotArg.device.name;
    const entities: IIntegrationEntity[] = [];

    entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
      key: 'light',
      platform: 'light',
      name: baseName,
      state: snapshotArg.light.on ? 'on' : 'off',
      available: snapshotArg.online,
      attributes: {
        brightness: snapshotArg.light.brightness255,
        brightnessPercent: snapshotArg.light.brightness,
        colorMode: snapshotArg.light.colorMode,
        supportedColorModes: snapshotArg.light.supportedColorModes,
        colorTempKelvin: snapshotArg.light.colorTemperatureKelvin,
        colorTempMired: snapshotArg.light.colorTemperatureMired,
        minColorTempKelvin: snapshotArg.light.minColorTemperatureKelvin,
        maxColorTempKelvin: snapshotArg.light.maxColorTemperatureKelvin,
        hsColor: snapshotArg.light.hue !== undefined || snapshotArg.light.saturation !== undefined ? [snapshotArg.light.hue ?? 0, snapshotArg.light.saturation ?? 0] : undefined,
        supportedFeatures: ['turn_on', 'turn_off', 'brightness', 'color_temp', ...snapshotArg.capabilities.color ? ['hs_color'] : []],
        source: snapshotArg.source,
        error: snapshotArg.error,
      },
    }));

    if (snapshotArg.battery) {
      for (const definition of batterySensorDefinitions) {
        const value = definition.value(snapshotArg.battery);
        if (value === undefined || value === null) {
          continue;
        }
        entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
          key: definition.key,
          platform: 'sensor',
          name: `${baseName} ${definition.name}`,
          state: value,
          available: snapshotArg.online,
          attributes: this.cleanAttributes({ unit: definition.unit, deviceClass: definition.deviceClass, stateClass: definition.stateClass }),
        }));
      }
    }

    if (snapshotArg.capabilities.batterySettings) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'bypass',
        platform: 'switch',
        name: `${baseName} Bypass`,
        state: snapshotArg.battery?.bypass ? 'on' : 'off',
        available: snapshotArg.online && snapshotArg.battery?.bypass !== undefined,
        attributes: { entityCategory: 'config' },
      }));
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'energy_saving',
        platform: 'switch',
        name: `${baseName} Energy Saving`,
        state: snapshotArg.battery?.energySavingEnabled ? 'on' : 'off',
        available: snapshotArg.online && snapshotArg.battery?.energySavingEnabled !== undefined,
        attributes: { entityCategory: 'config' },
      }));
    }

    entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
      key: 'identify',
      platform: 'button',
      name: `${baseName} Identify`,
      state: 'idle',
      available: snapshotArg.online && snapshotArg.capabilities.identify,
      attributes: { entityCategory: 'config', action: 'identify' },
    }));
    entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
      key: 'restart',
      platform: 'button',
      name: `${baseName} Restart`,
      state: 'idle',
      available: snapshotArg.online && snapshotArg.capabilities.restart,
      attributes: { entityCategory: 'config', action: 'restart' },
    }));

    return entities;
  }

  public static commandForService(snapshotArg: IElgatoSnapshot, requestArg: IServiceCallRequest): IElgatoCommandRequest | undefined {
    if (requestArg.domain === 'light') {
      if (requestArg.service === 'turn_on') {
        return this.lightCommand(snapshotArg, requestArg, true);
      }
      if (requestArg.service === 'turn_off') {
        return { action: 'set_light', on: false, service: requestArg.service, target: requestArg.target, data: requestArg.data };
      }
    }

    if (requestArg.domain === 'button' && requestArg.service === 'press') {
      return this.buttonCommand(snapshotArg, requestArg);
    }

    if (requestArg.domain === 'switch') {
      const enabled = requestArg.service === 'turn_on' ? true : requestArg.service === 'turn_off' ? false : undefined;
      if (enabled === undefined) {
        return undefined;
      }
      const target = this.targetText(requestArg);
      if (target.includes('bypass')) {
        return { action: 'battery_bypass', enabled, service: requestArg.service, target: requestArg.target, data: requestArg.data };
      }
      if (target.includes('energy')) {
        return { action: 'energy_saving', enabled, service: requestArg.service, target: requestArg.target, data: requestArg.data };
      }
    }

    if (requestArg.domain !== elgatoDomain) {
      return undefined;
    }

    if (requestArg.service === 'refresh') {
      return { action: 'refresh', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'identify') {
      return { action: 'identify', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'restart') {
      return { action: 'restart', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'turn_on') {
      return this.lightCommand(snapshotArg, requestArg, true);
    }
    if (requestArg.service === 'turn_off') {
      return { action: 'set_light', on: false, service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'set_light' || requestArg.service === 'light') {
      return this.lightCommand(snapshotArg, requestArg, this.booleanValue(requestArg.data?.on));
    }
    if (requestArg.service === 'battery_bypass') {
      const enabled = this.booleanValue(requestArg.data?.on ?? requestArg.data?.enabled);
      return enabled === undefined ? undefined : { action: 'battery_bypass', enabled, service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'energy_saving') {
      const enabled = this.booleanValue(requestArg.data?.on ?? requestArg.data?.enabled);
      return enabled === undefined ? undefined : { action: 'energy_saving', enabled, service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    return undefined;
  }

  public static deviceId(snapshotArg: IElgatoSnapshot): string {
    return `${elgatoDomain}.light.${this.uniqueBase(snapshotArg)}`;
  }

  public static uniqueBase(snapshotArg: IElgatoSnapshot): string {
    return this.slug(snapshotArg.device.serialNumber || snapshotArg.device.macAddress || snapshotArg.device.id || snapshotArg.device.host || snapshotArg.device.name || elgatoDomain);
  }

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

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

  public static compactMac(valueArg?: string): string | undefined {
    return this.normalizeMac(valueArg)?.replace(/[^a-fA-F0-9]/g, '').toLowerCase();
  }

  public static miredToKelvin(valueArg: number | undefined): number | undefined {
    return valueArg && Number.isFinite(valueArg) ? Math.round(1_000_000 / valueArg) : undefined;
  }

  public static kelvinToMired(valueArg: number | undefined): number | undefined {
    return valueArg && Number.isFinite(valueArg) ? Math.round(1_000_000 / valueArg) : undefined;
  }

  private static normalizeSnapshot(snapshotArg: IElgatoSnapshot, configArg: IElgatoConfig, sourceArg: TElgatoSnapshotSource): IElgatoSnapshot {
    const derived = this.toSnapshot({
      config: { ...configArg, snapshot: undefined },
      rawData: snapshotArg.rawData,
      online: snapshotArg.online,
      source: sourceArg,
      error: snapshotArg.error,
    });
    return {
      ...derived,
      ...snapshotArg,
      device: { ...derived.device, ...snapshotArg.device },
      light: { ...derived.light, ...snapshotArg.light },
      battery: snapshotArg.battery || derived.battery,
      capabilities: { ...derived.capabilities, ...snapshotArg.capabilities },
      rawData: snapshotArg.rawData || derived.rawData,
      updatedAt: snapshotArg.updatedAt || new Date().toISOString(),
      source: snapshotArg.source || sourceArg,
    };
  }

  private static rawData(configArg: IElgatoConfig, rawDataArg?: Partial<IElgatoRawData>): Partial<IElgatoRawData> {
    return this.cleanAttributes({
      ...configArg.rawData,
      ...rawDataArg,
      info: rawDataArg?.info || configArg.info || configArg.rawData?.info,
      settings: rawDataArg?.settings || configArg.settings || configArg.rawData?.settings,
      state: rawDataArg?.state || configArg.state || configArg.rawData?.state,
      battery: rawDataArg?.battery || configArg.battery || configArg.rawData?.battery,
      fetchedAt: rawDataArg?.fetchedAt || configArg.rawData?.fetchedAt,
    });
  }

  private static deviceInfo(configArg: IElgatoConfig, infoArg: IElgatoInfo | undefined, onlineArg: boolean): IElgatoDeviceSnapshotInfo {
    const endpoint = this.endpoint(configArg);
    const serialNumber = this.stringValue(infoArg?.serialNumber) || configArg.serialNumber;
    const macAddress = this.normalizeMac(this.stringValue(infoArg?.macAddress) || configArg.macAddress);
    const model = configArg.model || this.stringValue(infoArg?.productName);
    const name = configArg.name || this.stringValue(infoArg?.displayName) || serialNumber || endpoint.host || elgatoDisplayName;
    return this.cleanAttributes({
      id: configArg.uniqueId || serialNumber || macAddress || (endpoint.host ? `${endpoint.host}:${endpoint.port || elgatoDefaultPort}` : undefined) || name,
      name,
      manufacturer: configArg.manufacturer || elgatoManufacturer,
      model,
      serialNumber,
      firmwareVersion: this.stringValue(infoArg?.firmwareVersion),
      firmwareBuildNumber: this.numberValue(infoArg?.firmwareBuildNumber),
      hardwareBoardType: this.numberValue(infoArg?.hardwareBoardType),
      macAddress,
      host: endpoint.host,
      port: endpoint.port,
      baseUrl: endpoint.baseUrl,
      online: onlineArg,
    }) as IElgatoDeviceSnapshotInfo;
  }

  private static light(infoArg: IElgatoInfo | undefined, settingsArg: IElgatoSettings | undefined, stateArg: IElgatoState | undefined): IElgatoLightSnapshot {
    const productName = this.stringValue(infoArg?.productName) || '';
    const hue = this.numberValue(stateArg?.hue);
    const saturation = this.numberValue(stateArg?.saturation);
    const supportsColor = productName === 'Elgato Light Strip' || productName === 'Elgato Light Strip Pro' || settingsArg?.powerOnHue !== undefined || hue !== undefined;
    const brightness = this.clamp(this.numberValue(stateArg?.brightness) ?? 0, 0, 100);
    const temperature = this.numberValue(stateArg?.temperature);
    const supportedColorModes: TElgatoColorMode[] = supportsColor ? ['color_temp', 'hs'] : ['color_temp'];
    return this.cleanAttributes({
      on: this.booleanValue(stateArg?.on) ?? false,
      brightness,
      brightness255: Math.round((brightness * 255) / 100),
      colorMode: hue !== undefined ? 'hs' : 'color_temp',
      supportedColorModes,
      colorTemperatureMired: temperature,
      colorTemperatureKelvin: this.miredToKelvin(temperature),
      minColorTemperatureKelvin: supportsColor ? 3500 : 2900,
      maxColorTemperatureKelvin: supportsColor ? 6500 : 7000,
      hue,
      saturation,
    }) as IElgatoLightSnapshot;
  }

  private static battery(batteryArg: IElgatoBatteryInfo | undefined, settingsArg: IElgatoSettings | undefined): IElgatoBatterySnapshot | undefined {
    if (!batteryArg && !settingsArg?.battery) {
      return undefined;
    }
    const inputChargeVoltage = this.numberValue(batteryArg?.inputChargeVoltage);
    const inputChargeCurrent = this.numberValue(batteryArg?.inputChargeCurrent);
    return this.cleanAttributes({
      level: this.numberValue(batteryArg?.level),
      status: this.numberValue(batteryArg?.status),
      powerSource: this.numberValue(batteryArg?.powerSource),
      voltage: this.numberValue(batteryArg?.currentBatteryVoltage),
      inputChargeVoltage,
      inputChargeCurrent,
      chargePower: inputChargeVoltage !== undefined && inputChargeCurrent !== undefined ? Math.round((inputChargeVoltage * inputChargeCurrent) / 10_000) / 100 : undefined,
      bypass: this.booleanValue(settingsArg?.battery?.bypass),
      energySavingEnabled: this.booleanValue(settingsArg?.battery?.energySaving?.enable),
    }) as IElgatoBatterySnapshot;
  }

  private static entity(snapshotArg: IElgatoSnapshot, deviceIdArg: string, uniqueBaseArg: string, definitionArg: IElgatoEntityDefinition): IIntegrationEntity {
    return {
      id: `${definitionArg.platform}.${this.slug(definitionArg.name)}`,
      uniqueId: `${elgatoDomain}_${uniqueBaseArg}_${this.slug(definitionArg.key)}`,
      integrationDomain: elgatoDomain,
      deviceId: deviceIdArg,
      platform: definitionArg.platform,
      name: definitionArg.name,
      state: definitionArg.state,
      attributes: this.cleanAttributes({ key: definitionArg.key, ...definitionArg.attributes }),
      available: definitionArg.available,
    };
  }

  private static lightCommand(snapshotArg: IElgatoSnapshot, requestArg: IServiceCallRequest, onArg: boolean | undefined): IElgatoCommandRequest {
    const data = requestArg.data || {};
    const brightnessPercent = this.brightnessPercent(data);
    const hsColor = this.arrayValue(data.hs_color ?? data.hsColor);
    const colorTemperatureKelvin = this.numberValue(data.color_temp_kelvin ?? data.colorTempKelvin ?? data.kelvin);
    const temperature = this.numberValue(data.color_temp ?? data.colorTemp ?? data.temperature);
    const command: IElgatoCommandRequest = this.cleanAttributes({
      action: 'set_light',
      on: onArg,
      brightness: brightnessPercent,
      brightness255: this.numberValue(data.brightness),
      colorTemperatureKelvin,
      temperature,
      hue: hsColor ? this.numberValue(hsColor[0]) : this.numberValue(data.hue),
      saturation: hsColor ? this.numberValue(hsColor[1]) : this.numberValue(data.saturation),
      service: requestArg.service,
      target: requestArg.target,
      data: requestArg.data,
    }) as IElgatoCommandRequest;

    if (command.brightness !== undefined && command.hue === undefined && command.saturation === undefined && command.temperature === undefined && command.colorTemperatureKelvin === undefined && snapshotArg.capabilities.color && snapshotArg.light.colorMode === 'color_temp') {
      command.colorTemperatureKelvin = snapshotArg.light.colorTemperatureKelvin;
    }
    return command;
  }

  private static buttonCommand(snapshotArg: IElgatoSnapshot, requestArg: IServiceCallRequest): IElgatoCommandRequest | undefined {
    void snapshotArg;
    const target = this.targetText(requestArg);
    if (!target || target.includes('identify')) {
      return { action: 'identify', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (target.includes('restart')) {
      return { action: 'restart', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    return undefined;
  }

  private static brightnessPercent(dataArg: Record<string, unknown>): number | undefined {
    const brightnessPct = this.numberValue(dataArg.brightness_pct ?? dataArg.brightnessPct);
    if (brightnessPct !== undefined) {
      return Math.round(this.clamp(brightnessPct, 0, 100));
    }
    const brightness = this.numberValue(dataArg.brightness);
    return brightness === undefined ? undefined : Math.round((this.clamp(brightness, 0, 255) / 255) * 100);
  }

  private static targetText(requestArg: IServiceCallRequest): string {
    return [requestArg.target?.entityId, requestArg.target?.deviceId, requestArg.data?.entity_id, requestArg.data?.entityId, requestArg.data?.key, requestArg.data?.action].filter(Boolean).join(' ').toLowerCase();
  }

  private static endpoint(configArg: IElgatoConfig): { host?: string; port?: number; baseUrl?: string } {
    const parsed = this.parseEndpoint(configArg.url || configArg.host);
    if (parsed) {
      return parsed;
    }
    const host = configArg.host;
    const port = host ? configArg.port || elgatoDefaultPort : configArg.port;
    return {
      host,
      port,
      baseUrl: host ? `http://${this.hostForUrl(host)}${port && port !== 80 ? `:${port}` : ''}` : undefined,
    };
  }

  private static parseEndpoint(valueArg: string | undefined): { host: string; port: number; baseUrl: string } | undefined {
    if (!valueArg || !/^[a-z][a-z0-9+.-]*:\/\//i.test(valueArg)) {
      return undefined;
    }
    try {
      const url = new URL(valueArg);
      const port = url.port ? Number(url.port) : url.protocol === 'https:' ? 443 : elgatoDefaultPort;
      return { host: url.hostname, port, baseUrl: `${url.protocol}//${this.hostForUrl(url.hostname)}${url.port ? `:${url.port}` : ''}` };
    } catch {
      return undefined;
    }
  }

  private static hasCommandTransport(configArg: IElgatoConfig, actionArg: IElgatoCommandRequest['action']): boolean {
    if (configArg.commandExecutor || configArg.host || configArg.url) {
      return true;
    }
    if (actionArg === 'set_light') {
      return Boolean(configArg.client?.light || configArg.client?.execute);
    }
    if (actionArg === 'identify') {
      return Boolean(configArg.client?.identify || configArg.client?.execute);
    }
    if (actionArg === 'restart') {
      return Boolean(configArg.client?.restart || configArg.client?.execute);
    }
    if (actionArg === 'battery_bypass') {
      return Boolean(configArg.client?.batteryBypass || configArg.client?.execute);
    }
    if (actionArg === 'energy_saving') {
      return Boolean(configArg.client?.energySaving || configArg.client?.execute);
    }
    return Boolean(configArg.client?.execute);
  }

  private static hasRawData(rawDataArg: Partial<IElgatoRawData>): boolean {
    return Boolean(rawDataArg.info || rawDataArg.settings || rawDataArg.state || rawDataArg.battery);
  }

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

  private 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);
      return Number.isFinite(parsed) ? parsed : undefined;
    }
    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 (['1', 'true', 'yes', 'on'].includes(normalized)) {
        return true;
      }
      if (['0', 'false', 'no', 'off'].includes(normalized)) {
        return false;
      }
    }
    return undefined;
  }

  private static arrayValue(valueArg: unknown): unknown[] | undefined {
    return Array.isArray(valueArg) ? valueArg : undefined;
  }

  private static clamp(valueArg: number, minArg: number, maxArg: number): number {
    return Math.min(maxArg, Math.max(minArg, valueArg));
  }

  private static hostForUrl(hostArg: string): string {
    return hostArg.includes(':') && !hostArg.startsWith('[') ? `[${hostArg}]` : hostArg;
  }

  private static cleanAttributes<TRecord extends Record<string, unknown>>(recordArg: TRecord): TRecord {
    return Object.fromEntries(Object.entries(recordArg).filter(([, valueArg]) => valueArg !== undefined)) as TRecord;
  }

  private static clone<TValue>(valueArg: TValue): TValue {
    return JSON.parse(JSON.stringify(valueArg)) as TValue;
  }
}
