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 { IHegelConfig } from './hegel.types.js';
import { hegelDefaultPort, hegelProfile } from './hegel.types.js';

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

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

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

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

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

    const state = recordValue(rawDataArg.state) || rawDataArg;
    const hasHegelState = ['power', 'volume', 'mute', 'input', 'source', 'model'].some((keyArg) => keyArg in state || keyArg in rawDataArg);
    if (!hasHegelState) {
      return rawDataArg;
    }

    const host = configArg.host || stringValue(rawDataArg.host);
    const port = configArg.port || numberValue(rawDataArg.port) || (host ? hegelDefaultPort : undefined);
    const model = configArg.model || stringValue(rawDataArg.model) || stringValue(state.model) || hegelProfile.model;
    const name = configArg.name || stringValue(rawDataArg.name) || `${hegelProfile.manufacturer} ${model}`;
    const inputIndex = numberValue(state.input ?? state.sourceIndex ?? state.source_index);
    const sourceList = hegelInputNames(model);
    const source = stringValue(state.source) || (inputIndex ? sourceList[inputIndex - 1] : undefined);
    const volume = numberValue(state.volume);
    const maxVolume = configArg.maxVolume ?? configArg.max_volume ?? 1;
    const entity: ISimpleLocalEntitySnapshot = {
      id: 'media_player',
      name,
      platform: 'media_player',
      state: hegelState(state.power ?? state.state),
      writable: true,
      attributes: {
        volumeLevel: volume === undefined ? undefined : normalizeVolume(volume, maxVolume),
        isVolumeMuted: booleanValue(state.mute ?? state.muted),
        source,
        sourceList,
        model,
      },
    };

    return {
      device: {
        id: configArg.uniqueId || stringValue(rawDataArg.uniqueId) || (host ? `${host}:${port || ''}` : undefined) || name,
        name,
        manufacturer: 'Hegel',
        model,
        host,
        port,
        protocol: 'tcp',
      },
      entities: [entity],
      online: configArg.online ?? true,
      updatedAt: new Date().toISOString(),
      source: 'manual',
      rawData: rawDataArg,
    } satisfies ISimpleLocalSnapshot;
  }
}

const hegelModelInputs: Record<string, string[]> = {
  H95: ['Analog 1', 'Analog 2', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network'],
  H120: ['Balanced', 'Analog 1', 'Analog 2', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network'],
  H190: ['Balanced', 'Analog 1', 'Analog 2', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network'],
  H190V: ['XLR', 'Analog 1', 'Analog 2', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network', 'Phono'],
  H390: ['XLR', 'Analog 1', 'Analog 2', 'BNC', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network'],
  H590: ['XLR 1', 'XLR 2', 'Analog 1', 'Analog 2', 'Analog 3', 'BNC', 'Coaxial', 'Optical 1', 'Optical 2', 'Optical 3', 'USB', 'Network'],
};

const hegelInputNames = (modelArg: string | undefined): string[] => (modelArg && hegelModelInputs[modelArg]) || [];

const hegelState = (valueArg: unknown): string => {
  const power = booleanValue(valueArg);
  if (power !== undefined) {
    return power ? 'on' : 'off';
  }
  return stringValue(valueArg)?.toLowerCase() || 'unknown';
};

const normalizeVolume = (volumeArg: number, maxVolumeArg: number): number => {
  const level = volumeArg > 1 ? volumeArg / 100 : volumeArg;
  return Math.max(0, Math.min(level, maxVolumeArg || 1));
};

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;

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

const booleanValue = (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 (['1', 'true', 'yes', 'on'].includes(value)) {
    return true;
  }
  if (['0', 'false', 'no', 'off', 'standby'].includes(value)) {
    return false;
  }
  return undefined;
};
