import { Utils, ThumbnailInfo, MediaType, EventManager } from '@playkit-js/playkit-js';
import { Poster } from '@playkit-js/playkit-js-providers/types';
import evaluate from './utils/evaluate';
import { KalturaPlayer } from '../kaltura-player';
import { KPThumbnailConfig, UiConfig, KPMediaConfig } from '../types';

const DefaultThumbnailConfig: any = {
  thumbsWidth: 164,
  thumbsHeight: 92,
  thumbsSlices: 100
};

type ClipData = {
  seekFrom: number | undefined;
  clipTo: number | undefined;
};

const THUMBNAIL_REGEX = /.*\/p\/\d+\/(?:[a-zA-Z]+\/\d+\/)*thumbnail\/entry_id\/\w+\/.*\d+/;
const THUMBNAIL_SERVICE_TEMPLATE: string = '{{thumbnailUrl}}/width/{{thumbsWidth}}/vid_slices/{{thumbsSlices}}';

class ThumbnailManager {
  private _player: KalturaPlayer;
  private _thumbnailConfig: KPThumbnailConfig;
  private _eventManager: EventManager;
  private _thumbsHeight!: number;
  private _clipData: ClipData;
  private _uiConfig: UiConfig;
  private _mediaConfig: KPMediaConfig;

  constructor(player: KalturaPlayer, uiConfig: UiConfig, mediaConfig: KPMediaConfig) {
    this._player = player;
    this._uiConfig = uiConfig;
    this._mediaConfig = mediaConfig;
    this._clipData = this._buildClipData();
    this._thumbnailConfig = this._buildKalturaThumbnailConfig();
    this._eventManager = new EventManager();
    this._loadThumbnailImage();
  }

  private _loadThumbnailImage(): void {
    if (this._isUsingKalturaThumbnail()) {
      const img = new Image();
      this._eventManager.listenOnce(img, 'load', () => {
        this._thumbsHeight = img.naturalHeight;
      });
      img.src = this._thumbnailConfig?.thumbsSprite || '';
    }
  }

  private _buildClipData(): ClipData {
    return {
      seekFrom: this._mediaConfig.sources.seekFrom || Utils.Object.getPropertyPath(this._player.config.sources, 'seekFrom'),
      clipTo: this._mediaConfig.sources.clipTo || Utils.Object.getPropertyPath(this._player.config.sources, 'clipTo')
    };
  }

  public updateThumbnailKs(): void {
    this._thumbnailConfig = this._buildKalturaThumbnailConfig();
    this._loadThumbnailImage();
  }

  public destroy(): void {
    this._eventManager.destroy();
  }

  public getThumbnail(time: number): ThumbnailInfo | null {
    if (this._isUsingKalturaThumbnail()) {
      return this._convertKalturaThumbnailToThumbnailInfo(time);
    }
    // eslint-disable-next-line  @typescript-eslint/ban-ts-comment
    // @ts-ignore
    return this._player._localPlayer.getThumbnail(time);
  }

  public getKalturaThumbnailConfig(): KPThumbnailConfig {
    return this._thumbnailConfig;
  }

  private _isUsingKalturaThumbnail = (): boolean => {
    return !!(this._thumbnailConfig && this._thumbnailConfig.thumbsSprite);
  };

  private _convertKalturaThumbnailToThumbnailInfo = (time: number): ThumbnailInfo | null => {
    if (this._thumbnailConfig) {
      const { thumbsSprite, thumbsWidth, thumbsSlices } = this._thumbnailConfig;
      const duration = this._player.duration! / thumbsSlices;
      const thumbnailInfo = {
        x: Math.floor(time / duration) * thumbsWidth,
        y: 0,
        url: thumbsSprite,
        height: this._thumbsHeight,
        width: thumbsWidth
      };
      return new ThumbnailInfo(thumbnailInfo);
    }
    return null;
  };

  private _buildKalturaThumbnailConfig = (): KPThumbnailConfig => {
    const seekbarConfig = Utils.Object.getPropertyPath(this._uiConfig, 'components.seekbar');
    const rawThumbnailUrl = this._mediaConfig.sources?.rawThumbnailUrl;
    const isVod = this._mediaConfig.sources?.type === MediaType.VOD;
    const configKs = this._player.getUpdatedThumbnailKs() || this._mediaConfig.session?.ks || this._player.config.provider?.ks;
    const ks = this._player.shouldAddKs(this._mediaConfig) ? configKs : '';
    const thumbnailConfig = Utils.Object.mergeDeep(DefaultThumbnailConfig, seekbarConfig);
    const thumbsSprite = isVod ? this._getThumbSlicesUrl(rawThumbnailUrl, ks, thumbnailConfig) : '';
    return {
      thumbsSprite,
      ...thumbnailConfig
    };
  };

  private _maybeCutThumbnail = (baseUrl: string): string => {
    const { seekFrom, clipTo } = this._clipData;
    let url = baseUrl;
    if (typeof seekFrom === 'number') {
      url += `/start_sec/${seekFrom}`;
    }
    if (typeof clipTo === 'number') {
      url += `/end_sec/${clipTo}`;
    }
    return url;
  };

  private _getThumbSlicesUrl = (posterUrl: string | Poster[] | undefined, ks: string | undefined, thumbnailConfig: any): string => {
    if (typeof posterUrl === 'string') {
      if (THUMBNAIL_REGEX.test(posterUrl)) {
        try {
          const model: any = {
            thumbnailUrl: posterUrl,
            ...thumbnailConfig
          };
          const baseUrl = evaluate(THUMBNAIL_SERVICE_TEMPLATE, model);
          const url = this._maybeCutThumbnail(baseUrl);
          return ks ? url + `/ks/${ks}` : url;
        } catch (e) {
          return '';
        }
      }
    }
    return '';
  };
}

export { ThumbnailManager, THUMBNAIL_REGEX, DefaultThumbnailConfig };
