import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { SimpleLocalMapper, type IIntegrationEntity, type ISimpleLocalEntitySnapshot, type ISimpleLocalSnapshot, type ISimpleLocalSnapshotOptions, type TSimpleLocalRawData } from '../../core/index.js';
import type { IHisenseAehw4a1Config } from './hisense_aehw4a1.types.js';
import { hisenseAehw4a1DefaultName, hisenseAehw4a1Profile } from './hisense_aehw4a1.types.js';

const hvacModes = ['off', 'heat', 'cool', 'dry', 'fan_only'];
const fanModes = ['mute', 'low', 'medium', 'high', 'auto'];
const swingModes = ['off', 'vertical', 'horizontal', 'both'];
const presetModes = ['none', 'eco', 'boost', 'sleep', 'sleep_2', 'sleep_3', 'sleep_4'];

const acToHvacMode: Record<string, string> = {
  '0001': 'heat',
  '0010': 'cool',
  '0011': 'dry',
  '0000': 'fan_only',
};

const acToFanMode: Record<string, string> = {
  '00000000': 'auto',
  '00000001': 'auto',
  '00000010': 'mute',
  '00000100': 'low',
  '00000110': 'medium',
  '00001000': 'high',
};

const acToSwingMode: Record<string, string> = {
  '00': 'off',
  '10': 'vertical',
  '01': 'horizontal',
  '11': 'both',
};

export class HisenseAehw4a1Mapper {
  public static toSnapshot(optionsArg: Omit<ISimpleLocalSnapshotOptions<IHisenseAehw4a1Config>, 'profile'>): ISimpleLocalSnapshot {
    return SimpleLocalMapper.toSnapshot({
      ...optionsArg,
      profile: hisenseAehw4a1Profile,
      rawData: this.normalizeRawData(optionsArg.config, optionsArg.rawData),
    });
  }

  public static toSnapshotFromRaw(configArg: IHisenseAehw4a1Config, rawDataArg: TSimpleLocalRawData): ISimpleLocalSnapshot {
    return this.toSnapshot({ config: configArg, rawData: rawDataArg, online: true, source: 'manual' });
  }

  public static toDevices(snapshotArg: ISimpleLocalSnapshot): shxInterfaces.data.IDeviceDefinition[] {
    return SimpleLocalMapper.toDevices(hisenseAehw4a1Profile, snapshotArg);
  }

  public static toEntities(snapshotArg: ISimpleLocalSnapshot): IIntegrationEntity[] {
    return SimpleLocalMapper.toEntities(hisenseAehw4a1Profile, snapshotArg);
  }

  public static slug(valueArg: unknown): string {
    return SimpleLocalMapper.slug(valueArg);
  }

  private static normalizeRawData(configArg: IHisenseAehw4a1Config, rawDataArg: unknown): unknown {
    if (!isRecord(rawDataArg) || ('device' in rawDataArg && 'entities' in rawDataArg)) {
      return rawDataArg;
    }

    const status = recordValue(rawDataArg.status) || recordValue(rawDataArg.status_102_0) || rawDataArg;
    if (!('run_status' in status) && !('mode_status' in status) && !('indoor_temperature_status' in status)) {
      return rawDataArg;
    }

    const host = configArg.host || stringValue(rawDataArg.host) || stringValue(status.host);
    const id = configArg.uniqueId || host || stringValue(rawDataArg.id) || hisenseAehw4a1Profile.domain;
    const name = configArg.name || stringValue(rawDataArg.name) || host || hisenseAehw4a1DefaultName;
    const usesFahrenheit = status.temperature_Fahrenheit === '1' || status.temperatureFahrenheit === true;
    const temperatureUnit = usesFahrenheit ? 'F' : 'C';
    const on = status.run_status === '1' || status.runStatus === '1' || status.power === true || status.on === true;
    const hvacMode = on ? acToHvacMode[stringValue(status.mode_status ?? status.modeStatus) || ''] || stringValue(status.hvacMode) || 'unknown' : 'off';
    const currentTemperature = binaryNumber(status.indoor_temperature_status ?? status.indoorTemperatureStatus ?? status.currentTemperature);
    const targetTemperature = on && ['cool', 'heat'].includes(hvacMode) ? binaryNumber(status.indoor_temperature_setting ?? status.indoorTemperatureSetting ?? status.targetTemperature) : undefined;
    const swingCode = `${stringValue(status.up_down ?? status.upDown) || ''}${stringValue(status.left_right ?? status.leftRight) || ''}`;

    const entity: ISimpleLocalEntitySnapshot = {
      id: 'climate',
      uniqueId: `${hisenseAehw4a1Profile.domain}_${SimpleLocalMapper.slug(id)}_climate`,
      name: 'Climate',
      platform: 'climate',
      state: hvacMode,
      available: true,
      writable: true,
      attributes: {
        currentTemperature,
        targetTemperature,
        temperatureUnit,
        minTemperature: usesFahrenheit ? 61 : 16,
        maxTemperature: usesFahrenheit ? 90 : 32,
        fanMode: on ? acToFanMode[stringValue(status.wind_status ?? status.windStatus) || ''] || stringValue(status.fanMode) : undefined,
        fanModes,
        swingMode: on ? acToSwingMode[swingCode] || stringValue(status.swingMode) : undefined,
        swingModes,
        presetMode: on ? presetMode(status) : undefined,
        presetModes,
        hvacModes,
      },
    };

    return {
      device: {
        id,
        name,
        manufacturer: hisenseAehw4a1Profile.manufacturer,
        model: hisenseAehw4a1Profile.model,
        host,
        protocol: hisenseAehw4a1Profile.defaultProtocol,
        attributes: {
          upstreamCommand: 'status_102_0',
        },
      },
      entities: [entity],
      online: configArg.online ?? true,
      updatedAt: new Date().toISOString(),
      source: 'manual',
      rawData: rawDataArg,
    } satisfies ISimpleLocalSnapshot;
  }
}

const presetMode = (statusArg: Record<string, unknown>): string => {
  if (statusArg.efficient === '1') {
    return 'boost';
  }
  if (statusArg.low_electricity === '1') {
    return 'eco';
  }
  const sleepStatus = stringValue(statusArg.sleep_status ?? statusArg.sleepStatus);
  if (sleepStatus === '0000001') {
    return 'sleep';
  }
  if (sleepStatus === '0000010') {
    return 'sleep_2';
  }
  if (sleepStatus === '0000011') {
    return 'sleep_3';
  }
  if (sleepStatus === '0000100') {
    return 'sleep_4';
  }
  return 'none';
};

const binaryNumber = (valueArg: unknown): number | undefined => {
  if (typeof valueArg === 'number') {
    return valueArg;
  }
  if (typeof valueArg !== 'string' || !valueArg.trim()) {
    return undefined;
  }
  if (/^[01]+$/.test(valueArg)) {
    return Number.parseInt(valueArg, 2);
  }
  const parsed = Number(valueArg);
  return Number.isFinite(parsed) ? parsed : undefined;
};

const recordValue = (valueArg: unknown): Record<string, unknown> | undefined => isRecord(valueArg) ? valueArg : undefined;

const isRecord = (valueArg: unknown): valueArg is Record<string, unknown> => Boolean(valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg));

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