import {
  CrossOriginValue,
  IPlayableSource,
  IVideoOutput,
  PlayableMediaSource,
  PreloadType,
} from '../../types';

import { EngineState } from '../../../../constants';
import StateEngine from './state-engine';
import { IEventEmitter } from '../../../event-emitter/types';
import logger from '../../../../utils/logger';
import { getMimeByType, getMimeByUrl } from '../../../../utils/get-mime-type';
import { IChromecastDebugInfo } from './types';

const NOT_IMPLEMENTED = 'Not available using chromecast';

export default class ChromecastOutput implements IVideoOutput {
  type: string;

  private _playerController: cast.framework.RemotePlayerController;
  private _player: cast.framework.RemotePlayer;
  private _stateEngine: StateEngine;
  private _eventEmitter: IEventEmitter;
  private _src: string;

  private _isAutoplay: boolean;

  constructor(eventEmitter: IEventEmitter) {
    this._eventEmitter = eventEmitter;

    this._initRemote();
  }

  play() {
    if (this.isPaused) {
      this._playerController.playOrPause();
    }

    return Promise.resolve();
  }

  pause() {
    if (!this.isPaused) {
      this._playerController.playOrPause();
    }
  }

  setMute(mute: boolean) {
    if (mute === undefined) {
      return;
    }

    if (mute !== this.isMuted) {
      this._playerController.muteOrUnmute();
    }
  }

  setAutoplay(isAutoplay: boolean) {
    this._isAutoplay = isAutoplay;
  }

  setInline() {
    logger.warn(NOT_IMPLEMENTED);
  }

  setCrossOrigin() {
    logger.warn(NOT_IMPLEMENTED);
  }

  setCurrentTime(time: number) {
    this._player.currentTime = time;
    this._playerController.seek();
  }

  setVolume(volume: number) {
    if (this._player.volumeLevel === volume) {
      return;
    }

    this._player.volumeLevel = volume;
    this._playerController.setVolumeLevel();
  }

  setLoop() {
    logger.warn(NOT_IMPLEMENTED);
  }

  setPlaybackRate() {
    // TODO: https://developers.google.com/cast/docs/reference/chrome/chrome.cast.media.Media#playbackRate
    // Works only via receiver API
    logger.warn(NOT_IMPLEMENTED);
  }

  setPreload() {
    logger.warn(NOT_IMPLEMENTED);
  }

  setSrc(source: PlayableMediaSource, callback?: Function) {
    if (!source) {
      callback();
      return;
    }
    const cast = window.cast;
    const chrome = window.chrome;

    let calculatedSource = source;
    let mimeType, url;

    if (Array.isArray(source)) {
      calculatedSource = source[0];
    }

    if (typeof calculatedSource === 'string') {
      url = calculatedSource;
      mimeType = getMimeByUrl(calculatedSource);
    } else {
      calculatedSource = calculatedSource as IPlayableSource;
      mimeType = getMimeByType(calculatedSource.type);
      url = calculatedSource.url;
    }
    this._src = url;

    const session = cast.framework.CastContext.getInstance().getCurrentSession();
    const mediaInfo = new chrome.cast.media.MediaInfo(url, mimeType);
    const request = new chrome.cast.media.LoadRequest(mediaInfo);

    this._stateEngine.setState(EngineState.SRC_SET);

    session.loadMedia(request).then(() => {
      this._initRemote();
      this._stateEngine.setState(EngineState.PLAYING);

      if (typeof callback === 'function') {
        callback();
      }
    });
  }

  private _initRemote() {
    const cast = window.cast;

    this._player = new cast.framework.RemotePlayer();

    this._playerController = new cast.framework.RemotePlayerController(
      this._player,
    );

    this._stateEngine = new StateEngine(
      this._eventEmitter,
      this,
      this._playerController,
    );
  }

  getElement(): null {
    logger.warn(NOT_IMPLEMENTED);
    return null;
  }

  getDebugInfo() {
    return {
      output: 'chromecast',
      currentTime: this.currentTime,
      duration: this.duration,
      src: this.src,
    } as IChromecastDebugInfo;
  }

  get volume() {
    return this._player.volumeLevel;
  }

  get currentTime() {
    return this._player.currentTime;
  }

  get duration() {
    return this._player.duration;
  }

  get autoplay() {
    return this._isAutoplay;
  }

  get crossOrigin() {
    logger.warn(NOT_IMPLEMENTED);
    return 'anonymous' as CrossOriginValue;
  }

  get playbackRate() {
    return 1;
  }

  get buffered() {
    return {
      end: () => 0,
      start: () => 0,
      length: 0,
    };
  }

  get preload() {
    return PreloadType.AUTO;
  }

  get isPaused() {
    return this._player.isPaused;
  }

  get isMuted() {
    return this._player.isMuted;
  }

  get isEnded() {
    return this._stateEngine.state === EngineState.ENDED;
  }

  get isInline() {
    return false;
  }

  get isAutoplay() {
    return this._isAutoplay;
  }

  get isSeekAvailable() {
    return this._player.canSeek;
  }

  get isLoop() {
    return false;
  }

  get isPreloadActive() {
    return false;
  }

  get videoHeight() {
    return 0;
  }

  get videoWidth() {
    return 0;
  }

  get src() {
    return this._src;
  }

  get currentState(): EngineState {
    return this._stateEngine.state;
  }

  get isAutoPlayActive() {
    return false;
  }

  get isDynamicContent() {
    return false;
  }

  get isDynamicContentEnded() {
    return false;
  }

  get isMetadataLoaded() {
    return true;
  }

  get isSyncWithLive() {
    return false;
  }

  syncWithLive() {
    logger.warn(NOT_IMPLEMENTED);
  }
}
