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 { IGoogleWifiConfig } from './google_wifi.types.js';
import { googleWifiDefaultName, googleWifiProfile } from './google_wifi.types.js';

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

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

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

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

  private static normalizeRawData(configArg: IGoogleWifiConfig, rawDataArg: unknown): unknown {
    if (isSnapshotRecord(rawDataArg)) {
      return rawDataArg;
    }

    const rawObject = isRecord(rawDataArg) ? rawDataArg : undefined;
    const software = recordValue(rawObject?.software);
    const system = recordValue(rawObject?.system);
    const wan = recordValue(rawObject?.wan);
    if (!software && !system && !wan) {
      return rawDataArg;
    }

    const monitored = new Set(configArg.monitoredConditions || configArg.monitored_conditions || sensorKeys);
    const uptimeSeconds = numberValue(system?.uptime);
    const entities: ISimpleLocalEntitySnapshot[] = [];
    const addEntity = (idArg: string, nameArg: string, stateArg: unknown, attributesArg?: Record<string, unknown>) => {
      if (!monitored.has(idArg)) {
        return;
      }
      entities.push({
        id: idArg,
        name: nameArg,
        platform: 'sensor',
        state: stateArg,
        available: true,
        unit: idArg === 'uptime' ? 'd' : undefined,
        attributes: attributesArg,
      });
    };

    addEntity('current_version', 'Current version', software?.softwareVersion);
    addEntity('new_version', 'New version', software?.updateNewVersion === '0.0.0.0' ? 'Latest' : software?.updateNewVersion);
    addEntity('uptime', 'Uptime', uptimeSeconds !== undefined ? Math.round((uptimeSeconds / 86400) * 100) / 100 : undefined);
    addEntity('last_restart', 'Last restart', uptimeSeconds !== undefined ? new Date(Date.now() - uptimeSeconds * 1000).toISOString() : undefined, { sourceUptimeSeconds: uptimeSeconds });
    addEntity('local_ip', 'Local IP', wan?.online === false ? undefined : wan?.localIpAddress);
    addEntity('status', 'Status', wan?.online === false ? 'Offline' : wan?.online === true ? 'Online' : undefined);

    const host = configArg.host || stringValue(rawObject?.host);
    return {
      device: {
        id: configArg.uniqueId || host || configArg.name || googleWifiDefaultName,
        name: configArg.name || stringValue(rawObject?.name) || googleWifiDefaultName,
        manufacturer: googleWifiProfile.manufacturer,
        model: googleWifiProfile.model,
        host,
        protocol: host ? 'http' : 'local',
        configurationUrl: host ? `http://${host}` : undefined,
      },
      entities,
      online: configArg.online ?? wan?.online !== false,
      updatedAt: new Date().toISOString(),
      source: 'manual',
      rawData: rawDataArg,
    } satisfies ISimpleLocalSnapshot;
  }
}

const sensorKeys = ['current_version', 'new_version', 'uptime', 'last_restart', 'local_ip', 'status'];

const isSnapshotRecord = (valueArg: unknown): valueArg is ISimpleLocalSnapshot => Boolean(valueArg && typeof valueArg === 'object' && 'device' in valueArg && 'entities' in valueArg);

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

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

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

const numberValue = (valueArg: unknown): number | undefined => {
  const value = typeof valueArg === 'number' ? valueArg : typeof valueArg === 'string' && valueArg.trim() ? Number(valueArg) : undefined;
  return value !== undefined && Number.isFinite(value) ? value : undefined;
};
