import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import type { IDunehdSnapshot, IDunehdState } from './dunehd.types.js';
import { dunehdDefaultName } from './dunehd.types.js';

export class DunehdMapper {
  public static toDevices(snapshotArg: IDunehdSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const state = snapshotArg.state || {};
    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: 'dunehd',
      name: this.deviceName(snapshotArg),
      protocol: 'http',
      manufacturer: snapshotArg.deviceInfo.manufacturer || 'Dune',
      model: snapshotArg.deviceInfo.model,
      online: this.available(snapshotArg),
      features: [
        { id: 'power', capability: 'media', name: 'Power', readable: true, writable: true },
        { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: true },
        { id: 'current_title', capability: 'media', name: 'Current title', readable: true, writable: false },
        { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true, unit: '%' },
        { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
        { id: 'media_url', capability: 'media', name: 'Media URL', readable: true, writable: true },
        { id: 'remote_command', capability: 'media', name: 'Remote command', readable: false, writable: true },
      ],
      state: [
        { featureId: 'power', value: this.mediaState(state) === 'off' ? 'off' : 'on', updatedAt },
        { featureId: 'playback', value: this.mediaState(state), updatedAt },
        { featureId: 'current_title', value: this.mediaTitle(state) || null, updatedAt },
        { featureId: 'volume', value: this.volumePercent(state), updatedAt },
        { featureId: 'muted', value: this.isMuted(state), updatedAt },
        { featureId: 'media_url', value: state.playback_url || null, updatedAt },
      ],
      metadata: {
        host: snapshotArg.deviceInfo.host,
        port: snapshotArg.deviceInfo.port,
        serialNumber: snapshotArg.deviceInfo.serialNumber,
        macAddress: snapshotArg.deviceInfo.macAddress,
        firmwareVersion: snapshotArg.deviceInfo.firmwareVersion,
        playerState: state.player_state,
        playbackSpeed: state.playback_speed,
      },
    }];
  }

  public static toEntities(snapshotArg: IDunehdSnapshot): IIntegrationEntity[] {
    const state = snapshotArg.state || {};
    return [{
      id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
      uniqueId: `dunehd_${this.slug(this.identity(snapshotArg))}`,
      integrationDomain: 'dunehd',
      deviceId: this.deviceId(snapshotArg),
      platform: 'media_player',
      name: this.deviceName(snapshotArg),
      state: this.mediaState(state),
      attributes: {
        volumeLevel: this.volumeLevel(state),
        isVolumeMuted: this.isMuted(state),
        mediaTitle: this.mediaTitle(state),
        mediaContentId: state.playback_url,
        mediaContentType: this.mediaContentType(state),
        mediaDuration: this.numberValue(state.playback_duration),
        mediaPosition: this.numberValue(state.playback_position),
        playbackSpeed: this.numberValue(state.playback_speed),
        playerState: state.player_state,
        host: snapshotArg.deviceInfo.host,
        supportedFeatures: [
          'pause',
          'turn_on',
          'turn_off',
          'previous_track',
          'next_track',
          'play',
          'play_media',
          'browse_media',
          'volume_step',
          'volume_mute',
        ],
      },
      available: this.available(snapshotArg),
    }];
  }

  public static mediaState(stateArg: IDunehdState): string {
    let state = 'off';
    if ('playback_position' in stateArg) {
      state = 'playing';
    }
    if (stateArg.player_state === 'playing' || stateArg.player_state === 'buffering' || stateArg.player_state === 'photo_viewer') {
      state = 'playing';
    }
    if (this.numberValue(stateArg.playback_speed, 1234) === 0) {
      state = 'paused';
    }
    if (stateArg.player_state === 'navigator') {
      state = 'on';
    }
    return state;
  }

  public static mediaTitle(stateArg: IDunehdState): string | undefined {
    if (stateArg.player_state === 'bluray_playback') {
      return 'Blu-Ray';
    }
    if (stateArg.player_state === 'photo_viewer') {
      return 'Photo Viewer';
    }
    if (typeof stateArg.playback_url === 'string' && stateArg.playback_url) {
      return stateArg.playback_url.split('/').pop() || undefined;
    }
    return undefined;
  }

  public static deviceId(snapshotArg: IDunehdSnapshot): string {
    return `dunehd.device.${this.slug(this.identity(snapshotArg))}`;
  }

  private static available(snapshotArg: IDunehdSnapshot): boolean {
    return snapshotArg.online && Object.keys(snapshotArg.state || {}).length > 0;
  }

  private static mediaContentType(stateArg: IDunehdState): string | undefined {
    if (stateArg.player_state === 'photo_viewer') {
      return 'image';
    }
    if (stateArg.player_state === 'bluray_playback') {
      return 'video';
    }
    const url = typeof stateArg.playback_url === 'string' ? stateArg.playback_url.toLowerCase() : '';
    if (/\.(mp3|flac|aac|ogg|wav)(\?|$)/.test(url)) {
      return 'music';
    }
    if (/\.(jpg|jpeg|png|gif|webp)(\?|$)/.test(url)) {
      return 'image';
    }
    if (url) {
      return 'video';
    }
    return undefined;
  }

  private static volumeLevel(stateArg: IDunehdState): number {
    return this.volumePercent(stateArg) / 100;
  }

  private static volumePercent(stateArg: IDunehdState): number {
    return Math.max(0, Math.min(100, Math.round(this.numberValue(stateArg.playback_volume, 0))));
  }

  private static isMuted(stateArg: IDunehdState): boolean {
    if (typeof stateArg.playback_mute === 'boolean') {
      return stateArg.playback_mute;
    }
    return this.numberValue(stateArg.playback_mute, 0) === 1;
  }

  private static deviceName(snapshotArg: IDunehdSnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.deviceInfo.model || dunehdDefaultName;
  }

  private static identity(snapshotArg: IDunehdSnapshot): string {
    return snapshotArg.deviceInfo.id
      || snapshotArg.deviceInfo.serialNumber
      || snapshotArg.deviceInfo.macAddress
      || snapshotArg.deviceInfo.host
      || this.deviceName(snapshotArg);
  }

  private static numberValue(valueArg: unknown, fallbackArg?: number): number {
    if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg === 'string' && valueArg.trim()) {
      const parsed = Number(valueArg);
      return Number.isFinite(parsed) ? parsed : fallbackArg ?? 0;
    }
    return fallbackArg ?? 0;
  }

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