import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import type { IArcamFmjDeviceInfo, IArcamFmjSnapshot, IArcamFmjZoneState } from './arcam_fmj.types.js';

export class ArcamFmjMapper {
  public static toDevices(snapshotArg: IArcamFmjSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.lastUpdated || new Date().toISOString();
    return snapshotArg.zones.map((zoneArg) => {
      const volumeLevel = this.volumeLevel(zoneArg);
      const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
        { id: 'power', capability: 'media', name: 'Power', readable: true, writable: true },
        { id: 'source', capability: 'media', name: 'Source', readable: true, writable: true },
        { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true, unit: '%' },
        { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
      ];
      const state: plugins.shxInterfaces.data.IDeviceState[] = [
        { featureId: 'power', value: this.powerState(zoneArg), updatedAt },
        { featureId: 'source', value: zoneArg.source || null, updatedAt },
        { featureId: 'volume', value: typeof volumeLevel === 'number' ? Math.round(volumeLevel * 100) : null, updatedAt },
        { featureId: 'muted', value: typeof zoneArg.muted === 'boolean' ? zoneArg.muted : null, updatedAt },
      ];

      if (zoneArg.soundMode || zoneArg.soundModeList?.length) {
        features.push({ id: 'sound_mode', capability: 'media', name: 'Sound mode', readable: true, writable: true });
        state.push({ featureId: 'sound_mode', value: zoneArg.soundMode || null, updatedAt });
      }

      return {
        id: this.deviceId(snapshotArg, zoneArg),
        integrationDomain: 'arcam_fmj',
        name: this.deviceName(snapshotArg.deviceInfo, zoneArg),
        protocol: 'unknown',
        manufacturer: snapshotArg.deviceInfo.manufacturer || 'Arcam',
        model: snapshotArg.deviceInfo.model || 'Arcam FMJ AVR',
        online: zoneArg.available !== false,
        features,
        state,
        metadata: {
          host: snapshotArg.deviceInfo.host,
          port: snapshotArg.deviceInfo.port,
          zone: zoneArg.zone,
          revision: snapshotArg.deviceInfo.revision,
          serialNumber: snapshotArg.deviceInfo.serialNumber,
          uniqueId: snapshotArg.deviceInfo.uniqueId,
          apiModel: snapshotArg.deviceInfo.apiModel,
          viaDeviceId: zoneArg.zone === 1 ? undefined : this.mainDeviceId(snapshotArg),
        },
      };
    });
  }

  public static toEntities(snapshotArg: IArcamFmjSnapshot): IIntegrationEntity[] {
    return snapshotArg.zones.map((zoneArg) => ({
      id: `media_player.${this.entityBase(snapshotArg, zoneArg)}`,
      uniqueId: `arcam_fmj_${this.uniqueBase(snapshotArg)}_${zoneArg.zone}`,
      integrationDomain: 'arcam_fmj',
      deviceId: this.deviceId(snapshotArg, zoneArg),
      platform: 'media_player',
      name: this.deviceName(snapshotArg.deviceInfo, zoneArg),
      state: this.mediaState(zoneArg),
      attributes: {
        deviceClass: 'receiver',
        zone: zoneArg.zone,
        power: zoneArg.power,
        volume: zoneArg.volume,
        volumeLevel: this.volumeLevel(zoneArg),
        isVolumeMuted: zoneArg.muted,
        source: zoneArg.source,
        sourceList: zoneArg.sourceList,
        soundMode: zoneArg.soundMode,
        soundModeList: zoneArg.soundModeList,
        mediaContentType: zoneArg.media?.contentType,
        mediaContentId: zoneArg.media?.contentId,
        mediaTitle: zoneArg.media?.title || zoneArg.source,
        mediaArtist: zoneArg.media?.artist,
        mediaChannel: zoneArg.media?.channel,
        tunerPreset: zoneArg.tunerPreset,
        presets: zoneArg.presets,
        incomingVideo: zoneArg.incomingVideo,
        incomingAudio: zoneArg.incomingAudio,
      },
      available: zoneArg.available !== false,
    }));
  }

  public static deviceId(snapshotArg: IArcamFmjSnapshot, zoneArg: Pick<IArcamFmjZoneState, 'zone'>): string {
    const suffix = zoneArg.zone === 1 ? '' : `.zone_${zoneArg.zone}`;
    return `arcam_fmj.receiver.${this.uniqueBase(snapshotArg)}${suffix}`;
  }

  public static slug(valueArg: string | undefined): string {
    return (valueArg || 'arcam_fmj').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'arcam_fmj';
  }

  private static mediaState(zoneArg: IArcamFmjZoneState): string {
    if (zoneArg.power === false || zoneArg.state?.toLowerCase() === 'off') {
      return 'off';
    }
    if (zoneArg.power === true || zoneArg.state?.toLowerCase() === 'on') {
      return 'on';
    }
    return zoneArg.state || 'unknown';
  }

  private static powerState(zoneArg: IArcamFmjZoneState): string {
    return zoneArg.power === false || zoneArg.state?.toLowerCase() === 'off' ? 'off' : 'on';
  }

  private static volumeLevel(zoneArg: IArcamFmjZoneState): number | undefined {
    if (typeof zoneArg.volumeLevel === 'number') {
      return Math.max(0, Math.min(1, zoneArg.volumeLevel));
    }
    if (typeof zoneArg.volume === 'number') {
      return Math.max(0, Math.min(1, zoneArg.volume / 99));
    }
    return undefined;
  }

  private static mainDeviceId(snapshotArg: IArcamFmjSnapshot): string {
    return this.deviceId(snapshotArg, { zone: 1 });
  }

  private static deviceName(infoArg: IArcamFmjDeviceInfo, zoneArg: IArcamFmjZoneState): string {
    const receiverName = this.receiverName(infoArg);
    if (zoneArg.zone === 1) {
      return receiverName;
    }
    return `${receiverName} ${zoneArg.name || `Zone ${zoneArg.zone}`}`;
  }

  private static receiverName(infoArg: IArcamFmjDeviceInfo): string {
    return infoArg.name || infoArg.model || 'Arcam FMJ';
  }

  private static entityBase(snapshotArg: IArcamFmjSnapshot, zoneArg: IArcamFmjZoneState): string {
    const suffix = zoneArg.zone === 1 ? '' : `_zone_${zoneArg.zone}`;
    return `${this.slug(this.receiverName(snapshotArg.deviceInfo))}${suffix}`;
  }

  private static uniqueBase(snapshotArg: IArcamFmjSnapshot): string {
    return this.slug(snapshotArg.deviceInfo.uniqueId || snapshotArg.deviceInfo.serialNumber || snapshotArg.deviceInfo.model || snapshotArg.deviceInfo.host || this.receiverName(snapshotArg.deviceInfo));
  }
}
