'use strict';
import React, {Component, createRef} from 'react';

import {
  Alert,
  GestureResponderEvent,
  Platform,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

import Video, {FilterType, VideoRef, ResizeMode, IgnoreSilentSwitchType, MixWithOthersType} from 'react-native-video';

const filterTypes = [
  FilterType.NONE,
  FilterType.INVERT,
  FilterType.MONOCHROME,
  FilterType.POSTERIZE,
  FilterType.FALSE,
  FilterType.MAXIMUMCOMPONENT,
  FilterType.MINIMUMCOMPONENT,
  FilterType.CHROME,
  FilterType.FADE,
  FilterType.INSTANT,
  FilterType.MONO,
  FilterType.NOIR,
  FilterType.PROCESS,
  FilterType.TONAL,
  FilterType.TRANSFER,
  FilterType.SEPIA,
];

type SkinType = 'custom' | 'native' | 'embed'

type State = {
  rate: number,
  volume: number,
  muted: boolean,
  resizeMode: ResizeMode,
  duration: number,
  currentTime: number,
  controls: boolean,
  paused: boolean,
  skin: SkinType,
  ignoreSilentSwitch: IgnoreSilentSwitchType,
  mixWithOthers: MixWithOthersType,
  isBuffering: boolean,
  filter: FilterType,
  filterEnabled: boolean,
}

class VideoPlayer extends Component<{}, State> {
  controlRef: React.RefObject<TouchableOpacity>;
  videoRef: React.RefObject<VideoRef>;
  constructor(props: any) {
    super(props);
    this.onLoad = this.onLoad.bind(this);
    this.onProgress = this.onProgress.bind(this);
    this.onBuffer = this.onBuffer.bind(this);
    this.onTouchControl = this.onTouchControl.bind(this);
    this.controlRef = createRef();
    this.videoRef = createRef();
  }
  state: State = {
    rate: 1,
    volume: 1,
    muted: false,
    resizeMode: ResizeMode.CONTAIN,
    duration: 0.0,
    currentTime: 0.0,
    controls: false,
    paused: true,
    skin: 'custom',
    ignoreSilentSwitch: IgnoreSilentSwitchType.IGNORE,
    mixWithOthers: MixWithOthersType.DUCK,
    isBuffering: false,
    filter: FilterType.NONE,
    filterEnabled: true,
  };

  onLoad(data: any) {
    console.log('On load fired!');
    console.log(data.duration);
    this.setState({duration: data.duration});
  }

  onProgress(data: any) {
    this.setState({currentTime: data.currentTime});
  }

  onBuffer({isBuffering}: {isBuffering: boolean}) {
    this.setState({isBuffering});
  }

  onTouchControl(e: GestureResponderEvent) {
    if (!this.controlRef.current || !this.videoRef.current) return;
    const videoCommands = this.videoRef.current;
    const touchX = e.nativeEvent.pageX;
    const duration = this.state.duration;

    this.controlRef.current.measureInWindow((x, y, width, height) => {
      const relativeX = touchX - x;
      const nextTime = (relativeX / width) * duration;
      videoCommands.seek(nextTime);
    });
  }

  getCurrentTimePercentage() {
    if (this.state.currentTime > 0 && this.state.duration !== 0) {
      return this.state.currentTime / this.state.duration;
    } else {
      return 0;
    }
  }

  setFilter(step: number) {
    let index = filterTypes.indexOf(this.state.filter) + step;

    if (index === filterTypes.length) {
      index = 0;
    } else if (index === -1) {
      index = filterTypes.length - 1;
    }

    this.setState({
      filter: filterTypes[index],
    });
  }

  renderSkinControl(skin: 'custom' | 'native' | 'embed') {
    const isSelected = this.state.skin == skin;
    const selectControls = skin == 'native' || skin == 'embed';
    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({
            controls: selectControls,
            skin: skin,
          });
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {skin}
        </Text>
      </TouchableOpacity>
    );
  }

  renderRateControl(rate: number) {
    const isSelected = this.state.rate == rate;

    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({rate: rate});
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {rate}x
        </Text>
      </TouchableOpacity>
    );
  }

  renderResizeModeControl(resizeMode: ResizeMode) {
    const isSelected = this.state.resizeMode == resizeMode;

    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({resizeMode: resizeMode});
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {resizeMode}
        </Text>
      </TouchableOpacity>
    );
  }

  renderVolumeControl(volume: number) {
    const isSelected = this.state.volume == volume;

    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({volume: volume});
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {volume * 100}%
        </Text>
      </TouchableOpacity>
    );
  }

  renderIgnoreSilentSwitchControl(ignoreSilentSwitch: IgnoreSilentSwitchType) {
    const isSelected = this.state.ignoreSilentSwitch == ignoreSilentSwitch;

    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({ignoreSilentSwitch: ignoreSilentSwitch});
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {ignoreSilentSwitch}
        </Text>
      </TouchableOpacity>
    );
  }

  renderMixWithOthersControl(mixWithOthers: MixWithOthersType) {
    const isSelected = this.state.mixWithOthers == mixWithOthers;

    return (
      <TouchableOpacity
        onPress={() => {
          this.setState({mixWithOthers: mixWithOthers});
        }}>
        <Text
          style={[
            styles.controlOption,
            {fontWeight: isSelected ? 'bold' : 'normal'},
          ]}>
          {mixWithOthers}
        </Text>
      </TouchableOpacity>
    );
  }

  renderCustomSkin() {
    const flexCompleted = this.getCurrentTimePercentage() * 100;
    const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;

    return (
      <View style={styles.container}>
        <TouchableOpacity
          style={styles.fullScreen}
          onPress={() => {
            this.setState({paused: !this.state.paused});
          }}>
          <Video
            ref={this.videoRef}
            source={require('./broadchurch.mp4')}
            style={styles.fullScreen}
            rate={this.state.rate}
            paused={this.state.paused}
            volume={this.state.volume}
            muted={this.state.muted}
            ignoreSilentSwitch={this.state.ignoreSilentSwitch}
            mixWithOthers={this.state.mixWithOthers}
            resizeMode={this.state.resizeMode}
            onLoad={this.onLoad}
            onBuffer={this.onBuffer}
            onProgress={this.onProgress}
            onEnd={() => {
              Alert.alert('Done!');
            }}
            onError={e => {
              console.log(e);
            }}
            repeat={true}
            filter={this.state.filter}
            filterEnabled={this.state.filterEnabled}
          />
        </TouchableOpacity>

        <View style={styles.controls}>
          <View style={styles.generalControls}>
            <View style={styles.skinControl}>
              {this.renderSkinControl('custom')}
              {this.renderSkinControl('native')}
              {this.renderSkinControl('embed')}
            </View>
            {this.state.filterEnabled ? (
              <View style={styles.skinControl}>
                <TouchableOpacity
                  onPress={() => {
                    this.setFilter(-1);
                  }}>
                  <Text style={styles.controlOption}>Previous Filter</Text>
                </TouchableOpacity>
                <TouchableOpacity
                  onPress={() => {
                    this.setFilter(1);
                  }}>
                  <Text style={styles.controlOption}>Next Filter</Text>
                </TouchableOpacity>
              </View>
            ) : null}
          </View>
          <View style={styles.generalControls}>
            <View style={styles.rateControl}>
              {this.renderRateControl(0.5)}
              {this.renderRateControl(1.0)}
              {this.renderRateControl(2.0)}
            </View>

            <View style={styles.volumeControl}>
              {this.renderVolumeControl(0.5)}
              {this.renderVolumeControl(1)}
              {this.renderVolumeControl(1.5)}
            </View>

            <View style={styles.resizeModeControl}>
              {this.renderResizeModeControl(ResizeMode.COVER)}
              {this.renderResizeModeControl(ResizeMode.CONTAIN)}
              {this.renderResizeModeControl(ResizeMode.STRETCH)}
            </View>
          </View>
          <View style={styles.generalControls}>
            {Platform.OS === 'ios' ? (
              <>
                <View style={styles.ignoreSilentSwitchControl}>
                  {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.IGNORE)}
                  {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.OBEY)}
                </View>
                <View style={styles.mixWithOthersControl}>
                  {this.renderMixWithOthersControl(MixWithOthersType.MIX)}
                  {this.renderMixWithOthersControl(MixWithOthersType.DUCK)}
                </View>
              </>
            ) : null}
          </View>
          <TouchableOpacity ref={this.controlRef} onPress={this.onTouchControl}>
            <View style={styles.trackingControls}>
              <View style={styles.progress}>
                <View
                  style={[styles.innerProgressCompleted, {flex: flexCompleted}]}
                />
                <View
                  style={[styles.innerProgressRemaining, {flex: flexRemaining}]}
                />
              </View>
            </View>
          </TouchableOpacity>
        </View>
      </View>
    );
  }

  renderNativeSkin() {
    const videoStyle =
      this.state.skin == 'embed'
        ? styles.nativeVideoControls
        : styles.fullScreen;
    return (
      <View style={styles.container}>
        <View style={styles.fullScreen}>
          <Video
            ref={this.videoRef}
            source={require('./broadchurch.mp4')}
            style={videoStyle}
            rate={this.state.rate}
            paused={this.state.paused}
            volume={this.state.volume}
            muted={this.state.muted}
            ignoreSilentSwitch={this.state.ignoreSilentSwitch}
            mixWithOthers={this.state.mixWithOthers}
            resizeMode={this.state.resizeMode}
            onLoad={this.onLoad}
            onBuffer={this.onBuffer}
            onProgress={this.onProgress}
            onEnd={() => {
              Alert.alert('Done!');
            }}
            onError={e => {
              console.log(e);
            }}
            repeat={true}
            controls={this.state.controls}
            filter={this.state.filter}
            filterEnabled={this.state.filterEnabled}
          />
        </View>
        <View style={styles.controls}>
          <View style={styles.generalControls}>
            <View style={styles.skinControl}>
              {this.renderSkinControl('custom')}
              {this.renderSkinControl('native')}
              {this.renderSkinControl('embed')}
            </View>
            {this.state.filterEnabled ? (
              <View style={styles.skinControl}>
                <TouchableOpacity
                  onPress={() => {
                    this.setFilter(-1);
                  }}>
                  <Text style={styles.controlOption}>Previous Filter</Text>
                </TouchableOpacity>
                <TouchableOpacity
                  onPress={() => {
                    this.setFilter(1);
                  }}>
                  <Text style={styles.controlOption}>Next Filter</Text>
                </TouchableOpacity>
              </View>
            ) : null}
          </View>
          <View style={styles.generalControls}>
            <View style={styles.rateControl}>
              {this.renderRateControl(0.5)}
              {this.renderRateControl(1.0)}
              {this.renderRateControl(2.0)}
            </View>

            <View style={styles.volumeControl}>
              {this.renderVolumeControl(0.5)}
              {this.renderVolumeControl(1)}
              {this.renderVolumeControl(1.5)}
            </View>

            <View style={styles.resizeModeControl}>
              {this.renderResizeModeControl(ResizeMode.COVER)}
              {this.renderResizeModeControl(ResizeMode.CONTAIN)}
              {this.renderResizeModeControl(ResizeMode.STRETCH)}
            </View>
          </View>
          <View style={styles.generalControls}>
            {Platform.OS === 'ios' ? (
              <>
                <View style={styles.ignoreSilentSwitchControl}>
                  {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.IGNORE)}
                  {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.OBEY)}
                </View>
                <View style={styles.mixWithOthersControl}>
                  {this.renderMixWithOthersControl(MixWithOthersType.MIX)}
                  {this.renderMixWithOthersControl(MixWithOthersType.DUCK)}
                </View>
              </>
            ) : null}
          </View>
        </View>
      </View>
    );
  }

  render() {
    return this.state.controls
      ? this.renderNativeSkin()
      : this.renderCustomSkin();
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'black',
  },
  fullScreen: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
  controls: {
    backgroundColor: 'transparent',
    borderRadius: 5,
    position: 'absolute',
    bottom: 44,
    left: 4,
    right: 4,
  },
  progress: {
    flex: 1,
    flexDirection: 'row',
    borderRadius: 3,
    overflow: 'hidden',
  },
  innerProgressCompleted: {
    height: 20,
    backgroundColor: '#cccccc',
  },
  innerProgressRemaining: {
    height: 20,
    backgroundColor: '#2C2C2C',
  },
  generalControls: {
    flex: 1,
    flexDirection: 'row',
    overflow: 'hidden',
    paddingBottom: 10,
  },
  skinControl: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  rateControl: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  volumeControl: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
  },
  resizeModeControl: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  ignoreSilentSwitchControl: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  mixWithOthersControl: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  controlOption: {
    alignSelf: 'center',
    fontSize: 11,
    color: 'white',
    paddingLeft: 2,
    paddingRight: 2,
    lineHeight: 12,
  },
  nativeVideoControls: {
    top: 184,
    height: 300,
  },
  trackingControls: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
export default VideoPlayer;
