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 { IEmulatedKasaConfig } from './emulated_kasa.types.js';
import { emulatedKasaDefaultName, emulatedKasaProfile } from './emulated_kasa.types.js';

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

  public static toSnapshotFromRaw(configArg: IEmulatedKasaConfig, 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(emulatedKasaProfile, snapshotArg);
  }

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

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

  private static normalizeRawData(configArg: IEmulatedKasaConfig, rawDataArg: unknown): unknown {
    if (isSimpleSnapshot(rawDataArg)) {
      return rawDataArg;
    }

    const plugRecords = plugEntries(rawDataArg);
    if (!plugRecords.length) {
      return rawDataArg;
    }

    const rawRecord = recordValue(rawDataArg);
    const name = configArg.name || stringValue(rawRecord?.name) || emulatedKasaDefaultName;
    const host = configArg.host || stringValue(rawRecord?.host);
    const entities = plugRecords.flatMap(({ id, record }) => kasaEntities(id, record));
    if (!entities.length) {
      return rawDataArg;
    }

    return {
      device: {
        id: configArg.uniqueId || stringValue(rawRecord?.id) || host || emulatedKasaProfile.domain,
        name,
        manufacturer: emulatedKasaProfile.manufacturer,
        model: emulatedKasaProfile.model,
        host,
        port: configArg.port || numberValue(rawRecord?.port),
        protocol: emulatedKasaProfile.defaultProtocol,
        attributes: {
          emulatedPlugCount: plugRecords.length,
        },
      },
      entities,
      online: configArg.online ?? true,
      updatedAt: new Date().toISOString(),
      source: 'manual',
      rawData: rawDataArg,
    } satisfies ISimpleLocalSnapshot;
  }
}

const kasaEntities = (fallbackIdArg: string, recordArg: Record<string, unknown>): ISimpleLocalEntitySnapshot[] => {
  const entityId = stringValue(recordArg.entity_id) || stringValue(recordArg.entityId) || fallbackIdArg;
  const alias = stringValue(recordArg.name) || stringValue(recordArg.alias) || titleFromEntityId(entityId);
  const slug = SimpleLocalMapper.slug(entityId || alias);
  const domain = stringValue(recordArg.domain) || entityId.split('.')[0];
  const rawState = recordArg.state ?? recordArg.is_on ?? recordArg.isOn;
  const onState = switchState(rawState);
  const powerEntity = stringValue(recordArg.power_entity) || stringValue(recordArg.powerEntity);
  let power = numberValue(recordArg.power ?? recordArg.power_w ?? recordArg.powerW ?? recordArg.watts ?? recordArg.value);

  if (power === undefined && (domain === 'sensor' || entityId.startsWith('sensor.'))) {
    power = numberValue(rawState);
  }
  if (power === undefined && onState === false) {
    power = 0;
  }

  const entities: ISimpleLocalEntitySnapshot[] = [];
  if (power !== undefined) {
    entities.push({
      id: `${slug}_power`,
      uniqueId: `${emulatedKasaProfile.domain}_${slug}_power`,
      name: `${alias} Power`,
      platform: 'sensor',
      state: power,
      available: true,
      writable: false,
      unit: 'W',
      deviceClass: 'power',
      attributes: {
        entityId,
        powerEntity,
      },
    });
  }
  if (onState !== undefined && domain !== 'sensor') {
    entities.push({
      id: `${slug}_state`,
      uniqueId: `${emulatedKasaProfile.domain}_${slug}_state`,
      name: `${alias} State`,
      platform: 'binary_sensor',
      state: onState,
      available: true,
      writable: false,
      attributes: {
        entityId,
      },
    });
  }
  return entities;
};

const plugEntries = (valueArg: unknown): Array<{ id: string; record: Record<string, unknown> }> => {
  if (Array.isArray(valueArg)) {
    return valueArg.map((entryArg, indexArg) => ({ id: `plug_${indexArg + 1}`, record: recordValue(entryArg) })).filter((entryArg): entryArg is { id: string; record: Record<string, unknown> } => Boolean(entryArg.record));
  }

  const rawRecord = recordValue(valueArg);
  if (!rawRecord) {
    return [];
  }

  const nested = rawRecord.entities ?? rawRecord.plugs ?? rawRecord.devices;
  if (Array.isArray(nested)) {
    return plugEntries(nested);
  }
  const nestedRecord = recordValue(nested);
  if (nestedRecord) {
    return Object.entries(nestedRecord)
      .map(([idArg, entryArg]) => ({ id: idArg, record: recordValue(entryArg) }))
      .filter((entryArg): entryArg is { id: string; record: Record<string, unknown> } => Boolean(entryArg.record));
  }
  if ('power' in rawRecord || 'power_w' in rawRecord || 'powerW' in rawRecord || 'state' in rawRecord) {
    return [{ id: stringValue(rawRecord.entity_id) || stringValue(rawRecord.entityId) || stringValue(rawRecord.id) || 'plug', record: rawRecord }];
  }
  return [];
};

const switchState = (valueArg: unknown): boolean | undefined => {
  if (typeof valueArg === 'boolean') {
    return valueArg;
  }
  if (typeof valueArg === 'number') {
    return valueArg !== 0;
  }
  const value = stringValue(valueArg)?.toLowerCase();
  if (!value) {
    return undefined;
  }
  if (['on', 'true', '1', 'open', 'home'].includes(value)) {
    return true;
  }
  if (['off', 'false', '0', 'closed', 'not_home', 'unavailable', 'unknown'].includes(value)) {
    return false;
  }
  return undefined;
};

const titleFromEntityId = (valueArg: string): string => {
  const [, objectId = valueArg] = valueArg.split('.');
  return objectId.replace(/[_-]+/g, ' ').replace(/\b\w/g, (charArg) => charArg.toUpperCase());
};

const isSimpleSnapshot = (valueArg: unknown): valueArg is ISimpleLocalSnapshot => Boolean(recordValue(valueArg)?.device && Array.isArray(recordValue(valueArg)?.entities));
const recordValue = (valueArg: unknown): Record<string, unknown> | undefined => valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg) ? valueArg as Record<string, unknown> : undefined;
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() && Number.isFinite(Number(valueArg))) {
    return Number(valueArg);
  }
  return undefined;
};
