import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
import type {
  IGoodweCommandRequest,
  IGoodweConfig,
  IGoodweDeviceInfo,
  IGoodweRawData,
  IGoodweSensorDefinition,
  IGoodweSensorSnapshot,
  IGoodweSettingDefinition,
  IGoodweSettingSnapshot,
  IGoodweSnapshot,
  TGoodweOperationModeOption,
  TGoodweSnapshotSource,
} from './goodwe.types.js';
import {
  goodweDefaultUdpPort,
  goodweDisplayName,
  goodweDomain,
  goodweHomeAssistantOperationModeOptions,
  goodweManufacturer,
  goodweOperationModeValues,
  goodweOperationModes,
} from './goodwe.types.js';

interface IGoodweSnapshotOptions {
  config: IGoodweConfig;
  rawData?: Partial<IGoodweRawData>;
  online?: boolean;
  source?: TGoodweSnapshotSource;
  error?: string;
}

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

const mainSensorIds = new Set(['ppv', 'house_consumption', 'active_power', 'battery_soc', 'e_day', 'e_total', 'meter_e_total_exp', 'meter_e_total_imp', 'e_bat_charge_total', 'e_bat_discharge_total']);

const commonSensorNames: Record<string, string> = {
  ppv: 'PV Power',
  ppv1: 'PV1 Power',
  ppv2: 'PV2 Power',
  ppv3: 'PV3 Power',
  ppv4: 'PV4 Power',
  house_consumption: 'House Consumption',
  active_power: 'Active Power',
  battery_soc: 'Battery State of Charge',
  e_day: 'Energy Today',
  e_total: 'Energy Total',
  e_load_day: 'Load Energy Today',
  meter_e_total_exp: 'Meter Total Energy Export',
  meter_e_total_imp: 'Meter Total Energy Import',
  e_bat_charge_total: 'Battery Charge Total',
  e_bat_discharge_total: 'Battery Discharge Total',
  temperature: 'Temperature',
  grid_mode: 'Grid Mode',
  work_mode: 'Work Mode',
  timestamp: 'Timestamp',
};

const commonSensorUnits: Record<string, string> = {
  ppv: 'W',
  ppv1: 'W',
  ppv2: 'W',
  ppv3: 'W',
  ppv4: 'W',
  house_consumption: 'W',
  active_power: 'W',
  battery_soc: '%',
  e_day: 'kWh',
  e_total: 'kWh',
  e_load_day: 'kWh',
  meter_e_total_exp: 'kWh',
  meter_e_total_imp: 'kWh',
  e_bat_charge_total: 'kWh',
  e_bat_discharge_total: 'kWh',
};

const unitDescriptions: Record<string, { deviceClass?: string; stateClass?: string; unit?: string }> = {
  A: { deviceClass: 'current', stateClass: 'measurement', unit: 'A' },
  V: { deviceClass: 'voltage', stateClass: 'measurement', unit: 'V' },
  W: { deviceClass: 'power', stateClass: 'measurement', unit: 'W' },
  kWh: { deviceClass: 'energy', stateClass: 'total_increasing', unit: 'kWh' },
  VA: { deviceClass: 'apparent_power', stateClass: 'measurement', unit: 'VA' },
  var: { deviceClass: 'reactive_power', stateClass: 'measurement', unit: 'var' },
  C: { deviceClass: 'temperature', stateClass: 'measurement', unit: 'C' },
  '°C': { deviceClass: 'temperature', stateClass: 'measurement', unit: '°C' },
  Hz: { deviceClass: 'frequency', stateClass: 'measurement', unit: 'Hz' },
  h: { deviceClass: 'duration', stateClass: 'measurement', unit: 'h' },
  '%': { stateClass: 'measurement', unit: '%' },
};

export class GoodweMapper {
  public static toSnapshot(optionsArg: IGoodweSnapshotOptions): IGoodweSnapshot {
    if (optionsArg.config.snapshot && !optionsArg.rawData) {
      return this.normalizeSnapshot(this.clone(optionsArg.config.snapshot), optionsArg.config, optionsArg.source || 'snapshot', optionsArg.error);
    }

    const rawData = this.rawData(optionsArg.config, optionsArg.rawData);
    const hasData = this.hasUsableRawData(rawData);
    const device = this.inverterInfo(optionsArg.config, rawData);
    const runtimeData = rawData.runtimeData || {};
    const settingsData = rawData.settingsData || {};
    const settings = this.settingSnapshots(rawData, settingsData);
    const operationMode = this.operationMode(rawData.operationMode ?? settingsData.operation_mode ?? settingsData.work_mode);
    const supportedOperationModes = this.supportedOperationModes(rawData.supportedOperationModes, operationMode);
    const gridExportLimit = numberValue(rawData.gridExportLimit) ?? numberValue(settingsData.grid_export_limit);
    const batteryDischargeDepth = numberValue(rawData.batteryDischargeDepth) ?? numberValue(settingsData.battery_discharge_depth) ?? numberValue(settingsData.dod);
    const gridExportLimitUnit = settings.find((settingArg) => settingArg.id === 'grid_export_limit')?.unit === '%' ? '%' : 'W';
    const localControl = Boolean(optionsArg.config.commandExecutor || optionsArg.config.client?.execute);
    const localRead = Boolean(optionsArg.config.client || optionsArg.config.rawData || optionsArg.config.snapshot || hasData);
    const sensors = this.sensorSnapshots(rawData, runtimeData, Boolean(optionsArg.online ?? optionsArg.config.online ?? hasData));
    const online = optionsArg.online ?? optionsArg.config.online ?? hasData;
    const source = optionsArg.source || (hasData ? 'manual' : 'runtime');

    return {
      inverter: device,
      runtimeData: this.clone(runtimeData),
      settingsData: this.clone(settingsData),
      sensors,
      settings,
      controls: {
        operationMode,
        supportedOperationModes,
        gridExportLimit,
        gridExportLimitUnit,
        batteryDischargeDepth,
      },
      capabilities: {
        localRead,
        localControl,
        operationModeSelect: Boolean(operationMode || supportedOperationModes.length),
        gridExportLimitNumber: gridExportLimit !== undefined || settings.some((settingArg) => settingArg.id === 'grid_export_limit'),
        batteryDischargeDepthNumber: batteryDischargeDepth !== undefined || settings.some((settingArg) => settingArg.id === 'battery_discharge_depth' || settingArg.id === 'dod'),
        synchronizeClockButton: localControl && settings.some((settingArg) => settingArg.id === 'time'),
      },
      rawData: hasData ? this.clone(rawData) : undefined,
      online,
      updatedAt: rawData.fetchedAt || new Date().toISOString(),
      source,
      error: optionsArg.error,
    };
  }

  public static toDevices(snapshotArg: IGoodweSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'online', capability: 'sensor', name: 'Online', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'online', value: snapshotArg.online, updatedAt },
    ];

    for (const sensorId of ['ppv', 'house_consumption', 'active_power', 'battery_soc', 'e_day', 'e_total']) {
      const sensor = snapshotArg.sensors.find((sensorArg) => sensorArg.id === sensorId);
      if (!sensor) {
        continue;
      }
      features.push({ id: sensor.id, capability: sensor.unit === 'kWh' ? 'energy' : 'sensor', name: sensor.name || this.humanName(sensor.id), readable: true, writable: false, unit: sensor.unit });
      state.push({ featureId: sensor.id, value: this.deviceStateValue(sensor.value), updatedAt });
    }

    if (snapshotArg.capabilities.operationModeSelect) {
      features.push({ id: 'operation_mode', capability: 'sensor', name: 'Operation mode', readable: true, writable: snapshotArg.capabilities.localControl });
      state.push({ featureId: 'operation_mode', value: snapshotArg.controls.operationMode || null, updatedAt });
    }
    if (snapshotArg.capabilities.gridExportLimitNumber) {
      features.push({ id: 'grid_export_limit', capability: 'sensor', name: 'Grid export limit', readable: true, writable: snapshotArg.capabilities.localControl, unit: snapshotArg.controls.gridExportLimitUnit });
      state.push({ featureId: 'grid_export_limit', value: snapshotArg.controls.gridExportLimit ?? null, updatedAt });
    }

    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: goodweDomain,
      name: snapshotArg.inverter.name,
      protocol: 'unknown',
      manufacturer: snapshotArg.inverter.manufacturer,
      model: snapshotArg.inverter.model || snapshotArg.inverter.modelFamily || goodweDisplayName,
      online: snapshotArg.online,
      features,
      state,
      metadata: this.cleanAttributes({
        host: snapshotArg.inverter.host,
        port: snapshotArg.inverter.port,
        serialNumber: snapshotArg.inverter.serialNumber,
        modelFamily: snapshotArg.inverter.modelFamily,
        firmware: snapshotArg.inverter.firmware,
        armFirmware: snapshotArg.inverter.armFirmware,
        ratedPower: snapshotArg.inverter.ratedPower,
        source: snapshotArg.source,
        localRead: snapshotArg.capabilities.localRead,
        localControl: snapshotArg.capabilities.localControl,
        error: snapshotArg.error,
      }),
    }];
  }

  public static toEntities(snapshotArg: IGoodweSnapshot): IIntegrationEntity[] {
    const deviceId = this.deviceId(snapshotArg);
    const uniqueBase = this.uniqueBase(snapshotArg);
    const entities: IIntegrationEntity[] = [];

    for (const sensor of snapshotArg.sensors) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: sensor.id,
        entityIdKey: sensor.name || sensor.id,
        platform: 'sensor',
        name: `${snapshotArg.inverter.name} ${sensor.name || this.humanName(sensor.id)}`,
        state: sensor.value ?? null,
        available: sensor.available,
        attributes: this.cleanAttributes({
          key: sensor.id,
          unit: sensor.unit,
          deviceClass: sensor.id === 'battery_soc' ? 'battery' : sensor.deviceClass,
          stateClass: sensor.stateClass,
          kind: sensor.kind,
          entityCategory: sensor.entityCategory,
        }),
      }));
    }

    if (snapshotArg.capabilities.operationModeSelect) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'operation_mode',
        platform: 'select',
        name: `${snapshotArg.inverter.name} Inverter Operation Mode`,
        state: snapshotArg.controls.operationMode || null,
        available: snapshotArg.online && Boolean(snapshotArg.controls.operationMode),
        attributes: {
          options: snapshotArg.controls.supportedOperationModes,
          writable: snapshotArg.capabilities.localControl,
          entityCategory: 'config',
        },
      }));
    }

    if (snapshotArg.capabilities.gridExportLimitNumber) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'grid_export_limit',
        platform: 'number',
        name: `${snapshotArg.inverter.name} Grid Export Limit`,
        state: snapshotArg.controls.gridExportLimit ?? null,
        available: snapshotArg.online && snapshotArg.controls.gridExportLimit !== undefined,
        attributes: {
          unit: snapshotArg.controls.gridExportLimitUnit,
          min: 0,
          max: snapshotArg.controls.gridExportLimitUnit === '%' ? 200 : 10000,
          step: snapshotArg.controls.gridExportLimitUnit === '%' ? 1 : 100,
          writable: snapshotArg.capabilities.localControl,
          entityCategory: 'config',
        },
      }));
    }

    if (snapshotArg.capabilities.batteryDischargeDepthNumber) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'battery_discharge_depth',
        platform: 'number',
        name: `${snapshotArg.inverter.name} Depth of Discharge (On-Grid)`,
        state: snapshotArg.controls.batteryDischargeDepth ?? null,
        available: snapshotArg.online && snapshotArg.controls.batteryDischargeDepth !== undefined,
        attributes: {
          unit: '%',
          min: 0,
          max: 99,
          step: 1,
          writable: snapshotArg.capabilities.localControl,
          entityCategory: 'config',
        },
      }));
    }

    if (snapshotArg.capabilities.synchronizeClockButton) {
      entities.push(this.entity(snapshotArg, deviceId, uniqueBase, {
        key: 'synchronize_clock',
        platform: 'button',
        name: `${snapshotArg.inverter.name} Synchronize Inverter Clock`,
        state: 'available',
        available: snapshotArg.online,
        attributes: { entityCategory: 'config' },
      }));
    }

    return entities;
  }

  public static commandForService(snapshotArg: IGoodweSnapshot, requestArg: IServiceCallRequest): IGoodweCommandRequest | undefined {
    if (requestArg.domain === goodweDomain && requestArg.service === 'set_operation_mode') {
      const operationMode = this.operationMode(requestArg.data?.operationMode ?? requestArg.data?.operation_mode ?? requestArg.data?.mode ?? requestArg.data?.option);
      return operationMode ? { action: 'set_operation_mode', operationMode, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data } : undefined;
    }
    if (requestArg.domain === goodweDomain && requestArg.service === 'set_grid_export_limit') {
      const gridExportLimit = numberValue(requestArg.data?.value ?? requestArg.data?.gridExportLimit ?? requestArg.data?.grid_export_limit);
      return gridExportLimit === undefined ? undefined : { action: 'set_grid_export_limit', gridExportLimit, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.domain === goodweDomain && requestArg.service === 'set_battery_discharge_depth') {
      const batteryDischargeDepth = numberValue(requestArg.data?.value ?? requestArg.data?.batteryDischargeDepth ?? requestArg.data?.battery_discharge_depth);
      return batteryDischargeDepth === undefined ? undefined : { action: 'set_battery_discharge_depth', batteryDischargeDepth, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.domain === goodweDomain && ['synchronize_clock', 'sync_clock'].includes(requestArg.service)) {
      return { action: 'synchronize_clock', timestamp: stringValue(requestArg.data?.timestamp) || new Date().toISOString(), service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.domain === goodweDomain && ['write_setting', 'read_setting'].includes(requestArg.service)) {
      const settingId = stringValue(requestArg.data?.settingId) || stringValue(requestArg.data?.setting_id);
      if (!settingId) {
        return undefined;
      }
      return { action: requestArg.service, settingId, value: requestArg.data?.value, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }

    const targetEntityId = stringValue(requestArg.target.entityId);
    if (requestArg.domain === 'select' && requestArg.service === 'select_option' && targetEntityId?.includes('operation_mode')) {
      const operationMode = this.operationMode(requestArg.data?.option);
      return operationMode ? { action: 'set_operation_mode', operationMode, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data } : undefined;
    }
    if (requestArg.domain === 'number' && requestArg.service === 'set_value' && targetEntityId?.includes('grid_export_limit')) {
      const gridExportLimit = numberValue(requestArg.data?.value);
      return gridExportLimit === undefined ? undefined : { action: 'set_grid_export_limit', gridExportLimit, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.domain === 'number' && requestArg.service === 'set_value' && targetEntityId?.includes('battery_discharge_depth')) {
      const batteryDischargeDepth = numberValue(requestArg.data?.value);
      return batteryDischargeDepth === undefined ? undefined : { action: 'set_battery_discharge_depth', batteryDischargeDepth, service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.domain === 'button' && requestArg.service === 'press' && targetEntityId?.includes('synchronize_clock')) {
      return { action: 'synchronize_clock', timestamp: new Date().toISOString(), service: `${requestArg.domain}.${requestArg.service}`, target: requestArg.target, data: requestArg.data };
    }
    return undefined;
  }

  public static normalizeSensorDefinitions(valuesArg: unknown): IGoodweSensorDefinition[] | undefined {
    if (!Array.isArray(valuesArg)) {
      return undefined;
    }
    return valuesArg.map((valueArg) => this.sensorDefinitionFromRecord(valueArg)).filter((valueArg): valueArg is IGoodweSensorDefinition => Boolean(valueArg));
  }

  public static normalizeSettingDefinitions(valuesArg: unknown): IGoodweSettingDefinition[] | undefined {
    if (!Array.isArray(valuesArg)) {
      return undefined;
    }
    return valuesArg.map((valueArg) => this.settingDefinitionFromRecord(valueArg)).filter((valueArg): valueArg is IGoodweSettingDefinition => Boolean(valueArg));
  }

  public static deviceInfoFromRecord(recordArg: Record<string, unknown>): Partial<IGoodweDeviceInfo> {
    return this.cleanObject({
      name: stringValue(recordArg.name) || stringValue(recordArg.deviceName),
      model: stringValue(recordArg.model) || stringValue(recordArg.model_name) || stringValue(recordArg.modelName),
      modelName: stringValue(recordArg.model_name) || stringValue(recordArg.modelName),
      modelFamily: stringValue(recordArg.model_family) || stringValue(recordArg.modelFamily),
      serialNumber: stringValue(recordArg.serial_number) || stringValue(recordArg.serialNumber),
      firmware: stringValue(recordArg.firmware),
      armFirmware: stringValue(recordArg.arm_firmware) || stringValue(recordArg.armFirmware),
      ratedPower: numberValue(recordArg.rated_power) ?? numberValue(recordArg.ratedPower),
      acOutputType: numberValue(recordArg.ac_output_type) ?? numberValue(recordArg.acOutputType),
      dsp1Version: numberValue(recordArg.dsp1_version) ?? numberValue(recordArg.dsp1Version),
      dsp2Version: numberValue(recordArg.dsp2_version) ?? numberValue(recordArg.dsp2Version),
      dspSvnVersion: numberValue(recordArg.dsp_svn_version) ?? numberValue(recordArg.dspSvnVersion),
      armVersion: numberValue(recordArg.arm_version) ?? numberValue(recordArg.armVersion),
      armSvnVersion: numberValue(recordArg.arm_svn_version) ?? numberValue(recordArg.armSvnVersion),
    });
  }

  public static hasUsableRawData(rawDataArg: Partial<IGoodweRawData> | undefined): boolean {
    if (!rawDataArg) {
      return false;
    }
    return Boolean(
      rawDataArg.deviceInfo
      || Object.keys(rawDataArg.runtimeData || {}).length
      || Object.keys(rawDataArg.settingsData || {}).length
      || rawDataArg.sensors?.length
      || rawDataArg.settings?.length
      || rawDataArg.operationMode !== undefined
      || rawDataArg.gridExportLimit !== undefined
      || rawDataArg.batteryDischargeDepth !== undefined
    );
  }

  public static cleanObject<TValue extends Record<string, unknown>>(valueArg: TValue): TValue {
    return this.cleanAttributes(valueArg) as TValue;
  }

  public static cleanAttributes(valueArg: Record<string, unknown>): Record<string, unknown> {
    const result: Record<string, unknown> = {};
    for (const [key, value] of Object.entries(valueArg)) {
      if (value === undefined || value === null) {
        continue;
      }
      if (Array.isArray(value) && value.length === 0) {
        continue;
      }
      if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
        continue;
      }
      result[key] = value;
    }
    return result;
  }

  private static normalizeSnapshot(snapshotArg: IGoodweSnapshot, configArg: IGoodweConfig, sourceArg: TGoodweSnapshotSource, errorArg?: string): IGoodweSnapshot {
    return {
      ...snapshotArg,
      inverter: {
        ...snapshotArg.inverter,
        host: snapshotArg.inverter.host || configArg.host,
        port: snapshotArg.inverter.port || configArg.port || goodweDefaultUdpPort,
        name: configArg.name || snapshotArg.inverter.name || goodweDisplayName,
      },
      source: sourceArg,
      error: errorArg || snapshotArg.error,
    };
  }

  private static rawData(configArg: IGoodweConfig, rawDataArg?: Partial<IGoodweRawData>): IGoodweRawData {
    const source = rawDataArg || configArg.rawData || {};
    const deviceInfo = this.cleanObject({
      host: configArg.host,
      port: configArg.port,
      name: configArg.name,
      manufacturer: configArg.manufacturer,
      model: configArg.model,
      modelFamily: configArg.modelFamily,
      serialNumber: configArg.serialNumber,
      firmware: configArg.firmware,
      armFirmware: configArg.armFirmware,
      ratedPower: configArg.ratedPower,
      ...(source.deviceInfo || {}),
    });
    return {
      ...source,
      deviceInfo,
      runtimeData: source.runtimeData || runtimeDataFromLooseRawData(source),
      settingsData: source.settingsData || {},
      sensors: this.normalizeSensorDefinitions(source.sensors) || [],
      settings: this.normalizeSettingDefinitions(source.settings) || [],
      fetchedAt: source.fetchedAt,
    };
  }

  private static inverterInfo(configArg: IGoodweConfig, rawDataArg: IGoodweRawData): IGoodweSnapshot['inverter'] {
    const info = rawDataArg.deviceInfo || {};
    const serialNumber = info.serialNumber || configArg.serialNumber;
    const host = info.host || configArg.host;
    const port = info.port || configArg.port || (host ? goodweDefaultUdpPort : undefined);
    const model = info.model || info.modelName || configArg.model;
    const id = configArg.uniqueId || info.id || serialNumber || (host ? `${host}:${port || goodweDefaultUdpPort}` : 'goodwe');
    return {
      id,
      name: info.name || configArg.name || (serialNumber ? `GoodWe ${serialNumber}` : goodweDisplayName),
      host,
      port,
      manufacturer: info.manufacturer || configArg.manufacturer || goodweManufacturer,
      model,
      modelFamily: info.modelFamily || configArg.modelFamily || this.modelFamilyFromSerial(serialNumber),
      serialNumber,
      firmware: info.firmware || configArg.firmware,
      armFirmware: info.armFirmware || configArg.armFirmware,
      ratedPower: info.ratedPower || configArg.ratedPower,
      configurationUrl: 'https://www.semsportal.com',
    };
  }

  private static sensorSnapshots(rawDataArg: IGoodweRawData, runtimeDataArg: Record<string, unknown>, onlineArg: boolean): IGoodweSensorSnapshot[] {
    const definitionsById = new Map<string, IGoodweSensorDefinition>();
    for (const definition of rawDataArg.sensors || []) {
      if (!definition.id || definition.id.startsWith('xx')) {
        continue;
      }
      definitionsById.set(definition.id, definition);
    }
    for (const key of Object.keys(runtimeDataArg)) {
      if (key.startsWith('xx') || definitionsById.has(key)) {
        continue;
      }
      definitionsById.set(key, { id: key, name: commonSensorNames[key] || this.humanName(key), unit: commonSensorUnits[key] });
    }

    return [...definitionsById.values()].map((definitionArg) => {
      const value = runtimeDataArg[definitionArg.id];
      const unit = definitionArg.unit || commonSensorUnits[definitionArg.id];
      const description = unit ? unitDescriptions[unit] : undefined;
      return {
        ...definitionArg,
        name: definitionArg.name || commonSensorNames[definitionArg.id] || this.humanName(definitionArg.id),
        unit: description?.unit || unit,
        value,
        available: onlineArg && value !== undefined && value !== null,
        deviceClass: description?.deviceClass,
        stateClass: description?.stateClass,
        entityCategory: definitionArg.entityCategory || (mainSensorIds.has(definitionArg.id) ? undefined : 'diagnostic'),
      };
    });
  }

  private static settingSnapshots(rawDataArg: IGoodweRawData, settingsDataArg: Record<string, unknown>): IGoodweSettingSnapshot[] {
    const definitionsById = new Map<string, IGoodweSettingDefinition>();
    for (const definition of rawDataArg.settings || []) {
      if (!definition.id) {
        continue;
      }
      definitionsById.set(definition.id, definition);
    }
    for (const key of Object.keys(settingsDataArg)) {
      if (!definitionsById.has(key)) {
        definitionsById.set(key, { id: key, name: this.humanName(key) });
      }
    }
    return [...definitionsById.values()].map((definitionArg) => ({ ...definitionArg, value: settingsDataArg[definitionArg.id] }));
  }

  private static supportedOperationModes(valuesArg: unknown, activeModeArg?: TGoodweOperationModeOption): TGoodweOperationModeOption[] {
    const modes = Array.isArray(valuesArg) ? valuesArg.map((valueArg) => this.operationMode(valueArg)).filter((valueArg): valueArg is TGoodweOperationModeOption => Boolean(valueArg)) : [];
    const defaultModes = [...goodweHomeAssistantOperationModeOptions];
    const result = modes.length ? modes : activeModeArg ? defaultModes : [];
    return [...new Set(result)];
  }

  private static operationMode(valueArg: unknown): TGoodweOperationModeOption | undefined {
    if (typeof valueArg === 'number') {
      return goodweOperationModeValues[valueArg];
    }
    if (typeof valueArg === 'string' && valueArg.trim()) {
      const normalized = valueArg.trim().toLowerCase().replace(/[-\s]+/gu, '_');
      if (/^\d+$/u.test(normalized)) {
        return goodweOperationModeValues[Number(normalized)];
      }
      const byName = Object.values(goodweOperationModes).find((modeArg) => modeArg === normalized);
      if (byName) {
        return byName;
      }
      const enumName = normalized.replace(/^operationmode\./u, '');
      const enumMap: Record<string, TGoodweOperationModeOption> = {
        general: goodweOperationModes.general,
        off_grid: goodweOperationModes.offGrid,
        backup: goodweOperationModes.backup,
        eco: goodweOperationModes.eco,
        peak_shaving: goodweOperationModes.peakShaving,
        self_use: goodweOperationModes.selfUse,
        eco_charge: goodweOperationModes.ecoCharge,
        eco_discharge: goodweOperationModes.ecoDischarge,
      };
      return enumMap[enumName];
    }
    return undefined;
  }

  private static entity(snapshotArg: IGoodweSnapshot, deviceIdArg: string, uniqueBaseArg: string, definitionArg: IGoodweEntityDefinition): IIntegrationEntity {
    return {
      id: `${definitionArg.platform}.${this.slug(`${snapshotArg.inverter.name}_${definitionArg.entityIdKey || definitionArg.key}`)}`,
      uniqueId: `${goodweDomain}-${definitionArg.key}-${uniqueBaseArg}`,
      integrationDomain: goodweDomain,
      deviceId: deviceIdArg,
      platform: definitionArg.platform,
      name: definitionArg.name,
      state: definitionArg.state,
      attributes: this.cleanAttributes(definitionArg.attributes || {}),
      available: definitionArg.available ?? snapshotArg.online,
    };
  }

  private static deviceId(snapshotArg: IGoodweSnapshot): string {
    return `${goodweDomain}.inverter.${this.slug(this.uniqueBase(snapshotArg))}`;
  }

  private static uniqueBase(snapshotArg: IGoodweSnapshot): string {
    return snapshotArg.inverter.serialNumber || snapshotArg.inverter.id || snapshotArg.inverter.host || 'goodwe';
  }

  private static deviceStateValue(valueArg: unknown): plugins.shxInterfaces.data.TDeviceStateValue {
    if (typeof valueArg === 'string' || typeof valueArg === 'number' || typeof valueArg === 'boolean' || valueArg === null) {
      return valueArg;
    }
    if (valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg)) {
      return valueArg as Record<string, unknown>;
    }
    return valueArg === undefined ? null : String(valueArg);
  }

  private static sensorDefinitionFromRecord(valueArg: unknown): IGoodweSensorDefinition | undefined {
    if (!valueArg || typeof valueArg !== 'object') {
      return undefined;
    }
    const record = valueArg as Record<string, unknown>;
    const id = stringValue(record.id) || stringValue(record.id_) || stringValue(record.key);
    if (!id) {
      return undefined;
    }
    return this.cleanObject({
      id,
      name: stringValue(record.name),
      unit: stringValue(record.unit),
      kind: stringValue(record.kind),
      entityCategory: stringValue(record.entityCategory) || stringValue(record.entity_category),
      enabledByDefault: typeof record.enabledByDefault === 'boolean' ? record.enabledByDefault : undefined,
    }) as unknown as IGoodweSensorDefinition;
  }

  private static settingDefinitionFromRecord(valueArg: unknown): IGoodweSettingDefinition | undefined {
    const sensor = this.sensorDefinitionFromRecord(valueArg);
    if (!sensor || !valueArg || typeof valueArg !== 'object') {
      return sensor;
    }
    const record = valueArg as Record<string, unknown>;
    return this.cleanObject({
      ...sensor,
      writable: typeof record.writable === 'boolean' ? record.writable : undefined,
      min: numberValue(record.min),
      max: numberValue(record.max),
      step: numberValue(record.step),
    }) as unknown as IGoodweSettingDefinition;
  }

  private static modelFamilyFromSerial(serialNumberArg: string | undefined): string | undefined {
    if (!serialNumberArg) {
      return undefined;
    }
    const serial = serialNumberArg.toUpperCase();
    if (['ETU', 'ETL', 'ETR', 'BHN', 'EHU', 'BHU', 'EHR', 'BTU', 'ETT', 'HTA', 'HUB', 'EHB', 'HSB'].some((tagArg) => serial.includes(tagArg))) {
      return 'ET';
    }
    if (['ESU', 'EMU', 'ESA', 'BPS', 'BPU', 'EMJ', 'IJL'].some((tagArg) => serial.includes(tagArg))) {
      return 'ES';
    }
    if (['DTU', 'DTS', 'KMT', 'MSU', 'MST', 'MSC', 'DSN', 'DTN', 'DST', 'NSU', 'SSN', 'SST', 'SSX', 'SSY'].some((tagArg) => serial.includes(tagArg))) {
      return 'DT';
    }
    return undefined;
  }

  private static humanName(valueArg: string): string {
    return valueArg
      .replace(/_/gu, ' ')
      .replace(/\b\w/gu, (matchArg) => matchArg.toUpperCase())
      .replace(/Pv/gu, 'PV')
      .replace(/Soc/gu, 'SoC')
      .replace(/Ac\b/gu, 'AC')
      .replace(/Dc\b/gu, 'DC');
  }

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

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

const runtimeDataFromLooseRawData = (rawDataArg: Partial<IGoodweRawData>): Record<string, unknown> => {
  const reserved = new Set(['deviceInfo', 'runtimeData', 'settingsData', 'sensors', 'settings', 'operationMode', 'supportedOperationModes', 'gridExportLimit', 'batteryDischargeDepth', 'fetchedAt']);
  const runtimeData: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(rawDataArg)) {
    if (!reserved.has(key) && isRuntimeValue(value)) {
      runtimeData[key] = value;
    }
  }
  return runtimeData;
};

const isRuntimeValue = (valueArg: unknown): boolean => {
  return ['string', 'number', 'boolean'].includes(typeof valueArg) || valueArg === null;
};

const stringValue = (valueArg: unknown): string | undefined => typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;

const 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(/[^0-9+-.]/gu, ''));
    return Number.isFinite(parsed) ? parsed : undefined;
  }
  return undefined;
};
