import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import type { IKodiMediaItem, IKodiSnapshot, IKodiTime } from './kodi.types.js';

const kodiMediaTypes: Record<string, string> = {
  music: 'music',
  artist: 'music',
  album: 'music',
  song: 'music',
  audio: 'music',
  video: 'video',
  musicvideo: 'video',
  movie: 'movie',
  episode: 'episode',
  tvshow: 'tvshow',
  season: 'tvshow',
  channel: 'channel',
  set: 'playlist',
};

export class KodiMapper {
  public static toDevices(snapshotArg: IKodiSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const application = snapshotArg.application;
    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: 'kodi',
      name: this.deviceName(snapshotArg),
      protocol: 'http',
      manufacturer: snapshotArg.deviceInfo.manufacturer || 'Kodi',
      model: snapshotArg.deviceInfo.model || application?.name,
      online: snapshotArg.online,
      features: [
        { id: 'playback', capability: 'media', name: 'Playback', 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 },
        { id: 'active_player', capability: 'media', name: 'Active player', readable: true, writable: false },
        { id: 'current_title', capability: 'media', name: 'Current title', readable: true, writable: false },
        { id: 'notification', capability: 'media', name: 'Notification', readable: false, writable: true },
      ],
      state: [
        { featureId: 'playback', value: this.mediaState(snapshotArg), updatedAt },
        { featureId: 'volume', value: typeof application?.volume === 'number' ? application.volume : null, updatedAt },
        { featureId: 'muted', value: typeof application?.muted === 'boolean' ? application.muted : null, updatedAt },
        { featureId: 'active_player', value: snapshotArg.player?.type || null, updatedAt },
        { featureId: 'current_title', value: this.mediaTitle(snapshotArg.item) || null, updatedAt },
      ],
      metadata: {
        uuid: snapshotArg.deviceInfo.uuid,
        host: snapshotArg.deviceInfo.host,
        port: snapshotArg.deviceInfo.port,
        wsPort: snapshotArg.deviceInfo.wsPort,
        version: snapshotArg.deviceInfo.version,
        activePlayerId: snapshotArg.player?.playerid,
      },
    }];
  }

  public static toEntities(snapshotArg: IKodiSnapshot): IIntegrationEntity[] {
    const item = snapshotArg.item;
    return [{
      id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
      uniqueId: `kodi_${this.uniqueBase(snapshotArg)}`,
      integrationDomain: 'kodi',
      deviceId: this.deviceId(snapshotArg),
      platform: 'media_player',
      name: this.deviceName(snapshotArg),
      state: this.mediaState(snapshotArg),
      attributes: {
        volumeLevel: typeof snapshotArg.application?.volume === 'number' ? snapshotArg.application.volume / 100 : undefined,
        isVolumeMuted: snapshotArg.application?.muted,
        mediaContentId: this.mediaContentId(item),
        mediaContentType: this.mediaContentType(snapshotArg),
        mediaDuration: snapshotArg.playerProperties?.live ? undefined : this.seconds(snapshotArg.playerProperties?.totaltime),
        mediaPosition: this.seconds(snapshotArg.playerProperties?.time),
        mediaTitle: this.mediaTitle(item),
        mediaSeriesTitle: item?.showtitle,
        mediaSeason: item?.season,
        mediaEpisode: item?.episode,
        mediaAlbumName: item?.album,
        mediaArtist: this.firstString(item?.artist),
        mediaAlbumArtist: this.firstString(item?.albumartist),
        mediaImageUrl: item?.thumbnail,
        playerId: snapshotArg.player?.playerid,
        playerType: snapshotArg.player?.type,
        live: snapshotArg.playerProperties?.live,
        dynamicRange: this.dynamicRange(item),
      },
      available: snapshotArg.online,
    }];
  }

  private static mediaState(snapshotArg: IKodiSnapshot): string {
    if (!snapshotArg.online) {
      return 'off';
    }
    if (!snapshotArg.players.length) {
      return 'idle';
    }
    if (snapshotArg.playerProperties?.speed === 0) {
      return 'paused';
    }
    if (typeof snapshotArg.playerProperties?.speed === 'number') {
      return 'playing';
    }
    return 'idle';
  }

  private static mediaContentType(snapshotArg: IKodiSnapshot): string | undefined {
    const itemType = snapshotArg.item?.type;
    if (itemType && kodiMediaTypes[itemType]) {
      return kodiMediaTypes[itemType];
    }
    const playerType = snapshotArg.player?.type;
    return playerType ? kodiMediaTypes[playerType] || playerType : undefined;
  }

  private static mediaContentId(itemArg: IKodiMediaItem | undefined): unknown {
    if (!itemArg) {
      return undefined;
    }
    if (typeof itemArg.uniqueid === 'string') {
      return itemArg.uniqueid;
    }
    if (itemArg.uniqueid && typeof itemArg.uniqueid === 'object') {
      const values = Object.values(itemArg.uniqueid).filter((valueArg) => valueArg !== undefined);
      return values[0];
    }
    return itemArg.id;
  }

  private static mediaTitle(itemArg: IKodiMediaItem | undefined): string | undefined {
    return itemArg?.title || itemArg?.label || itemArg?.file;
  }

  private static dynamicRange(itemArg: IKodiMediaItem | undefined): string | undefined {
    if (!itemArg) {
      return undefined;
    }
    return itemArg.streamdetails?.video?.[0]?.hdrtype || 'sdr';
  }

  private static seconds(timeArg: IKodiTime | undefined): number | undefined {
    if (!timeArg) {
      return undefined;
    }
    return (timeArg.hours || 0) * 3600 + (timeArg.minutes || 0) * 60 + (timeArg.seconds || 0) + (timeArg.milliseconds || 0) / 1000;
  }

  private static firstString(valueArg: string[] | string | undefined): string | undefined {
    return Array.isArray(valueArg) ? valueArg[0] : valueArg;
  }

  private static deviceId(snapshotArg: IKodiSnapshot): string {
    return `kodi.device.${this.uniqueBase(snapshotArg)}`;
  }

  private static uniqueBase(snapshotArg: IKodiSnapshot): string {
    return this.slug(snapshotArg.deviceInfo.uuid || snapshotArg.deviceInfo.id || snapshotArg.deviceInfo.host || this.deviceName(snapshotArg));
  }

  private static deviceName(snapshotArg: IKodiSnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.application?.name || 'Kodi';
  }

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