import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Placeholder } from 'semantic-ui-react';
import { assocPath, keys, omit, path, prop } from 'ramda';

import DefaultItem from '../Item/Item';
import getJwplayerSetup from './getJwplayersetup';
import getImageUrlByWidth from '../MediaImage/getImageUrlByWidth';
import filterSizesByAspectRatio from '../MediaImage/filterSizesByAspectRatio';
import JwPlayer from '../JwPlayer';
import CustomPropTypes from '../../lib/customPropTypes';
import { withSite } from '../../addons/Site';

export const propTypes = {
  /** Desired aspect ratio. */
  aspectRatio: CustomPropTypes.aspectRatio,

  /** ID of the video medium. */
  id: PropTypes.number.isRequired,

  /** Configuration for JWPlayer. */
  jwPlayerConfig: PropTypes.object,

  /**
   * Called after the player is mounted.
   * @param {Object} jwPlayer - Player object.
   */
  onPlayerMounted: PropTypes.func,

  /** Content to display while awaiting data. */
  placeholder: PropTypes.element,

  /** ID of the poster medium. */
  posterId: PropTypes.number,

  /** Width based on img src will be chosen. */
  posterWidth: PropTypes.number.isRequired,

  /**
   * StoryShare `Site`.
   * @private
   */
  site: PropTypes.object.isRequired,
};

/* Defaults */
const defaultProps = {
  placeholder: <Placeholder><Placeholder.Image rectangular /></Placeholder>,
  aspectRatio: '16:9',
};

/**
 * Media video - fetches video and renders jwplayer
 * The following props are required.
 * Additional props will be passed through to <JwPlayer> component.
 * @returns {Object} component
 */
export class MediaVideo extends Component {
  /**
   * The value of the video's current time as a percentage
   * Used to send track event to GA at different time intervals
   */
  currentTimePercentage = 0

  /**
   * Boolean that is used to keep track of whether seek
   * has been requested either by scrubbing the control bar
   */
  seeking = false;

  /**
   * Filters through available images sizes to get an appropriate url
   * @param {object} imageMedium - Image to get url from.
   * @param {string} mediumAspectRatio - Aspect ratio to use to find url.
   * @returns {string} Image url
   */
  getImageUrlByWidth = (imageMedium, mediumAspectRatio) => {
    const { aspectRatio, posterWidth } = this.props;

    // Gets the available sizes an image has
    const imageSizes = path(['media_details', 'sizes'], imageMedium);

    // Filters through sizes available
    // to get the correct ones using aspectRatio from parent component or video
    const filteredSizes = filterSizesByAspectRatio(
      imageSizes,
      aspectRatio || mediumAspectRatio,
    );

    // Gets a image url for specific width
    const imageSizeUrl = getImageUrlByWidth(
      posterWidth,
      filteredSizes
    );

    return imageSizeUrl;
  }

  /**
   * Renders the JwPlayer component
   * @param {object} jwPlayerConfig - Configuration for JWPlayer.
   * @returns {Object} component
   */
  renderJwPlayer = (jwPlayerConfig) => (
    <JwPlayer
      jwPlayerConfig={ jwPlayerConfig }
      onPlayerMounted={ this.handlePlayerMounted }
      { ...omit(keys(propTypes), this.props) }
    />
  );

  /**
   * Helper function to keep track of video progress
   * @param {number} currentTimePercentage - Percentage value of video
   *                                       current time position
   * @returns {void}
   */
  updatePlayerProgress = (currentTimePercentage) => {
    if (currentTimePercentage >= 10 && currentTimePercentage < 25) {
      this.reportTimedProgress(10);
    } else if (currentTimePercentage >= 25 && currentTimePercentage < 50) {
      this.reportTimedProgress(25);
    } else if (currentTimePercentage >= 50 && currentTimePercentage < 75) {
      this.reportTimedProgress(50);
    } else if (currentTimePercentage >= 75 && currentTimePercentage < 90) {
      this.reportTimedProgress(75);
    } else if (currentTimePercentage >= 90 && currentTimePercentage < 91) {
      this.reportTimedProgress(90);
    }
  }

  /**
   * Helper function to send track event to GA
   * @param {number} progress - current percentage value the video
   * @returns {void}
   */
  reportTimedProgress = (progress) => {
    const { site, id } = this.props;

    if (progress > this.currentTimePercentage) {
      site.trackEvent(
        site.ANALYTICS_TYPE.MEDIA,
        {
          action: `${progress}%`,
          objectRoute: `media/${id}`,
          interactive: false,
        }
      );
    }
  }

  /**
   * Handle jwplayer events
   * @param {object} jwplayer - Video player
   * @returns {void}
   */
  handlePlayerMounted = (jwplayer) => {
    const { id, site, onPlayerMounted } = this.props;

    if (onPlayerMounted) {
      onPlayerMounted(jwplayer);
    }

    jwplayer.on('play', () => {
      site.trackEvent(
        site.ANALYTICS_TYPE.MEDIA,
        { action: 'play', objectRoute: `media/${id}` }
      );
    });

    jwplayer.on('pause', () => {
      site.trackEvent(
        site.ANALYTICS_TYPE.MEDIA,
        { action: 'pause', objectRoute: `media/${id}` }
      );
    });

    jwplayer.on('complete', () => {
      site.trackEvent(
        site.ANALYTICS_TYPE.MEDIA,
        { action: 'ended', objectRoute: `media/${id}` }
      );
    });

    jwplayer.on('time', ({ duration: videoDuration, currentTime }) => {
      if (!this.seeking) {
        const currentTimePercentage = (currentTime / videoDuration) * 100;
        this.updatePlayerProgress(currentTimePercentage);
        this.currentTimePercentage = currentTimePercentage;
      }
    });

    jwplayer.on('seek', () => {
      this.seeking = true;
    });

    jwplayer.on('seeked', () => {
      this.seeking = false;
    });
  }

  render = () => {
    const {
      aspectRatio,
      id,
      posterId,
      placeholder,
      site,
      jwPlayerConfig,
    } = this.props;

    return (
      <DefaultItem id={ id } typeSlug="media" placeholder={ placeholder }>
        { (medium) => {
          const offlineMedium = site.objectToResponse(medium).offline();

          // featured_media is the id of the video's featured image
          // playback contains extra information about video i.e subtitle
          const { featured_media: featuredMedia, playback } = offlineMedium;

          let setup
            = getJwplayerSetup(jwPlayerConfig, offlineMedium, aspectRatio);

          if (posterId || featuredMedia) {
            return (
              <DefaultItem
                id={ posterId || featuredMedia }
                typeSlug="media"
                placeholder={ placeholder }
              >
                { (image) => {
                  // Retrieves offline version of image
                  const offlineImage = site.objectToResponse(image).offline();

                  const mediumAspectRatio
                   = prop('aspect_ratio', playback) || aspectRatio;

                  const imageUrl = this.getImageUrlByWidth(
                    offlineImage,
                    mediumAspectRatio
                  );

                  setup = assocPath(['playlist', 0, 'image'], imageUrl, setup);

                  return this.renderJwPlayer(setup);
                } }
              </DefaultItem>
            );
          }

          return this.renderJwPlayer(setup);
        } }
      </DefaultItem>
    );
  }
}

MediaVideo.propTypes = propTypes;
MediaVideo.defaultProps = defaultProps;

export default withSite(MediaVideo);
