import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import type { IChannelsFavoriteChannel, IChannelsNowPlaying, IChannelsSnapshot, IChannelsStatusChannel } from './channels.types.js';

const defaultImageUrl = 'https://getchannels.com/assets/img/icon-1024.png';

export class ChannelsMapper {
  public static toDevices(snapshotArg: IChannelsSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: 'channels',
      name: this.deviceName(snapshotArg),
      protocol: 'http',
      manufacturer: snapshotArg.deviceInfo.manufacturer || 'Fancy Bits',
      model: snapshotArg.deviceInfo.model || 'Channels',
      online: snapshotArg.online,
      features: [
        { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: true },
        { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
        { id: 'channel', capability: 'media', name: 'Channel', readable: true, writable: true },
        { id: 'current_title', capability: 'media', name: 'Current title', readable: true, writable: false },
        { id: 'episode_title', capability: 'media', name: 'Episode title', readable: true, writable: false },
        { id: 'summary', capability: 'media', name: 'Summary', readable: true, writable: false },
      ],
      state: [
        { featureId: 'playback', value: this.mediaState(snapshotArg), updatedAt },
        { featureId: 'muted', value: snapshotArg.status.muted ?? null, updatedAt },
        { featureId: 'channel', value: this.channelNumber(snapshotArg.status.channel) ?? null, updatedAt },
        { featureId: 'current_title', value: this.nowPlaying(snapshotArg)?.title || null, updatedAt },
        { featureId: 'episode_title', value: this.episodeTitle(this.nowPlaying(snapshotArg)) || null, updatedAt },
        { featureId: 'summary', value: this.nowPlaying(snapshotArg)?.summary || null, updatedAt },
      ],
      metadata: {
        host: snapshotArg.deviceInfo.host,
        port: snapshotArg.deviceInfo.port,
        channelName: this.channelName(snapshotArg.status.channel),
        channelNumber: this.channelNumber(snapshotArg.status.channel),
        status: snapshotArg.status.status,
        favoriteChannels: snapshotArg.favoriteChannels,
      },
    }];
  }

  public static toEntities(snapshotArg: IChannelsSnapshot): IIntegrationEntity[] {
    const channel = snapshotArg.status.channel;
    const nowPlaying = this.nowPlaying(snapshotArg);
    return [{
      id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
      uniqueId: `channels_${this.uniqueBase(snapshotArg)}`,
      integrationDomain: 'channels',
      deviceId: this.deviceId(snapshotArg),
      platform: 'media_player',
      name: this.deviceName(snapshotArg),
      state: this.mediaState(snapshotArg),
      attributes: {
        isVolumeMuted: snapshotArg.status.muted,
        mediaContentId: this.channelNumber(channel),
        mediaContentType: 'channel',
        mediaTitle: nowPlaying?.title,
        mediaEpisodeTitle: this.episodeTitle(nowPlaying),
        mediaSeason: this.numberValue(nowPlaying?.season_number ?? nowPlaying?.seasonNumber),
        mediaEpisode: this.numberValue(nowPlaying?.episode_number ?? nowPlaying?.episodeNumber),
        mediaSummary: nowPlaying?.summary,
        mediaImageUrl: this.mediaImageUrl(snapshotArg),
        source: this.channelName(channel),
        sourceList: snapshotArg.favoriteChannels.map((channelArg) => this.channelName(channelArg)).filter((channelArg): channelArg is string => Boolean(channelArg)),
        channelNumber: this.channelNumber(channel),
        channelName: this.channelName(channel),
        status: snapshotArg.status.status,
      },
      available: snapshotArg.online,
    }];
  }

  public static deviceId(snapshotArg: IChannelsSnapshot): string {
    return `channels.device.${this.uniqueBase(snapshotArg)}`;
  }

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

  public static channelNumber(channelArg: IChannelsStatusChannel | IChannelsFavoriteChannel | undefined): string | undefined {
    const value = channelArg?.channel_number ?? channelArg?.number;
    return value === undefined || value === null ? undefined : String(value);
  }

  public static channelName(channelArg: IChannelsStatusChannel | IChannelsFavoriteChannel | undefined): string | undefined {
    return channelArg?.channel_name || channelArg?.name || channelArg?.call_sign;
  }

  public static channelImageUrl(channelArg: IChannelsStatusChannel | IChannelsFavoriteChannel | undefined): string | undefined {
    return channelArg?.channel_image_url || channelArg?.image_url;
  }

  public static mediaImageUrl(snapshotArg: IChannelsSnapshot): string {
    const nowPlaying = this.nowPlaying(snapshotArg);
    return nowPlaying?.image_url || nowPlaying?.imageUrl || this.channelImageUrl(snapshotArg.status.channel) || defaultImageUrl;
  }

  private static mediaState(snapshotArg: IChannelsSnapshot): string {
    if (!snapshotArg.online) {
      return 'off';
    }
    if (snapshotArg.status.status === 'stopped') {
      return 'idle';
    }
    if (snapshotArg.status.status === 'paused') {
      return 'paused';
    }
    if (snapshotArg.status.status === 'playing') {
      return 'playing';
    }
    return snapshotArg.status.status || 'unknown';
  }

  private static nowPlaying(snapshotArg: IChannelsSnapshot): IChannelsNowPlaying | undefined {
    return snapshotArg.status.now_playing || snapshotArg.status.nowPlaying;
  }

  private static episodeTitle(nowPlayingArg: IChannelsNowPlaying | undefined): string | undefined {
    return nowPlayingArg?.episode_title || nowPlayingArg?.episodeTitle;
  }

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

  private static deviceName(snapshotArg: IChannelsSnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.deviceInfo.host || 'Channels';
  }

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