import { UIUtils } from './UIUtils';
import { DOM } from '../DOM';
import { PlayerAPI } from 'bitmovin-player';
import { VolumeController } from './VolumeController';

export enum SeekBarType {
  Vod,
  Live,
  Volume,
}

interface Range {
  min: number;
  max: number;
}

interface KeyStepIncrementsConfig {
  leftRight: number;
  upDown: number;
}

const coerceValueIntoRange = (value: number, range: Range, cb: (value: number) => void) => {
  if (value < range.min) {
    cb(range.min);
  } else if (value > range.max) {
    cb(range.max);
  } else {
    cb(value);
  }
};

/**
 * @category Utils
 */
export class SeekBarController {
  protected keyStepIncrements: KeyStepIncrementsConfig;
  protected player: PlayerAPI;
  protected volumeController: VolumeController;

  constructor(keyStepIncrements: KeyStepIncrementsConfig, player: PlayerAPI, volumeController: VolumeController) {
    this.keyStepIncrements = keyStepIncrements;
    this.player = player;
    this.volumeController = volumeController;
  }

  protected arrowKeyControls(currentValue: number, range: Range, valueUpdate: (value: number) => void) {
    const controlValue = Math.floor(currentValue);

    return {
      left: () => coerceValueIntoRange(controlValue - this.keyStepIncrements.leftRight, range, valueUpdate),
      right: () => coerceValueIntoRange(controlValue + this.keyStepIncrements.leftRight, range, valueUpdate),
      up: () => coerceValueIntoRange(controlValue + this.keyStepIncrements.upDown, range, valueUpdate),
      down: () => coerceValueIntoRange(controlValue - this.keyStepIncrements.upDown, range, valueUpdate),
      home: () => coerceValueIntoRange(range.min, range, valueUpdate),
      end: () => coerceValueIntoRange(range.max, range, valueUpdate),
    };
  }

  protected seekBarControls(type: SeekBarType) {
    if (type === SeekBarType.Live) {
      return this.arrowKeyControls(
        this.player.getTimeShift(),
        { min: this.player.getMaxTimeShift(), max: 0 },
        (value: number) => this.player.timeShift(value),
      );
    } else if (type === SeekBarType.Vod) {
      return this.arrowKeyControls(
        this.player.getCurrentTime(),
        { min: 0, max: this.player.getDuration() },
        (value: number) => this.player.seek(value),
      );
    } else if (type === SeekBarType.Volume && this.volumeController != null) {
      const volumeTransition = this.volumeController.startTransition();
      return this.arrowKeyControls(
        this.player.getVolume(),
        { min: 0, max: 100 },
        volumeTransition.finish.bind(volumeTransition),
      );
    }
  }

  public setSeekBarControls(domElement: DOM, type: () => SeekBarType) {
    domElement.on('keydown', (e: KeyboardEvent) => {
      const controls = this.seekBarControls(type());
      switch (e.keyCode) {
        case UIUtils.KeyCode.LeftArrow: {
          controls.left();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.RightArrow: {
          controls.right();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.UpArrow: {
          controls.up();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.DownArrow: {
          controls.down();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.Home: {
          controls.home();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.End: {
          controls.end();
          e.preventDefault();
          break;
        }
        case UIUtils.KeyCode.Space: {
          this.player.isPlaying() ? this.player.pause() : this.player.play();
          e.preventDefault();
          break;
        }
      }
    });
  }
}
