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 { IHitronCodaConfig } from './hitron_coda.types.js';
import { hitronCodaDefaultName, hitronCodaProfile } from './hitron_coda.types.js';

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

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

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

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

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

    const rawRecord = recordValue(rawDataArg);
    const clients = recordsValue(Array.isArray(rawDataArg) ? rawDataArg : rawRecord?.devices ?? rawRecord?.clients ?? rawRecord?.connectedDevices ?? rawRecord?.connectInfo ?? rawRecord?.data);
    if (!clients.length) {
      return rawDataArg;
    }

    const host = configArg.host || stringValue(rawRecord?.host);
    const id = configArg.uniqueId || host || hitronCodaProfile.domain;
    const name = configArg.name || stringValue(rawRecord?.name) || hitronCodaDefaultName;
    const entities: ISimpleLocalEntitySnapshot[] = [
      {
        id: 'connected_devices',
        uniqueId: `${hitronCodaProfile.domain}_${SimpleLocalMapper.slug(id)}_connected_devices`,
        name: 'Connected Devices',
        platform: 'sensor',
        state: clients.length,
        available: true,
        writable: false,
        unit: 'devices',
        attributes: {
          sourcePath: '/data/getConnectInfo.asp',
        },
      },
      ...clients.map((clientArg) => clientEntity(id, clientArg)).filter((entityArg): entityArg is ISimpleLocalEntitySnapshot => Boolean(entityArg)),
    ];

    return {
      device: {
        id,
        name,
        manufacturer: hitronCodaProfile.manufacturer,
        model: hitronCodaProfile.model,
        host,
        protocol: hitronCodaProfile.defaultProtocol,
        configurationUrl: host ? `http://${host}` : undefined,
        attributes: {
          routerType: configArg.routerType || configArg.type || stringValue(rawRecord?.type),
          loginPath: '/goform/login',
          clientsPath: '/data/getConnectInfo.asp',
        },
      },
      entities,
      online: configArg.online ?? true,
      updatedAt: new Date().toISOString(),
      source: 'manual',
      rawData: rawDataArg,
    } satisfies ISimpleLocalSnapshot;
  }
}

const clientEntity = (hubIdArg: string, clientArg: Record<string, unknown>): ISimpleLocalEntitySnapshot | undefined => {
  const macAddress = macValue(clientArg.macAddr ?? clientArg.mac_address ?? clientArg.macAddress ?? clientArg.mac);
  if (!macAddress) {
    return undefined;
  }
  const hostName = stringValue(clientArg.hostName ?? clientArg.hostname ?? clientArg.name) || macAddress;
  return {
    id: `client_${SimpleLocalMapper.slug(macAddress)}`,
    uniqueId: `${hitronCodaProfile.domain}_${SimpleLocalMapper.slug(hubIdArg)}_${SimpleLocalMapper.slug(macAddress)}`,
    name: hostName,
    platform: 'binary_sensor',
    state: true,
    available: true,
    writable: false,
    deviceClass: 'presence',
    attributes: {
      macAddress,
      ipAddress: stringValue(clientArg.ipAddr ?? clientArg.ip_address ?? clientArg.ipAddress),
      interface: stringValue(clientArg.interface ?? clientArg.iface),
      connectionType: stringValue(clientArg.type ?? clientArg.connectionType),
    },
  };
};

const macValue = (valueArg: unknown): string | undefined => stringValue(valueArg)?.toUpperCase();

const recordsValue = (valueArg: unknown): Array<Record<string, unknown>> => Array.isArray(valueArg) ? valueArg.filter(isRecord) : [];

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;
