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

import { withSite } from '../../addons/Site';
import { printError } from '../../lib';
import getImageUrlByWidth from './getImageUrlByWidth';
import filterSizesByAspectRatio from './filterSizesByAspectRatio';
import CustomPropTypes from '../../lib/customPropTypes';
import DefaultItem from '../Item/Item';

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

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

  /**
   * Loaded medium.
   * @private
   */
  medium: PropTypes.shape({
    media_details: PropTypes.shape({
      sizes: PropTypes.object.isRequired,
    }).isRequired,
  }),

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

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

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

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

/**
 * Media image
 * The following props are required.
 * Additional props will be passed through to SUI's <Image> component.
 * @returns {Object} component
 */
export class MediaImage extends Component {
  state = { error: false };

  handleError = () => this.setState({ error: true });

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

    // StoryShare sets `featured_media` to `0` if none has been selected
    if (id === 0) {
      return null;
    }

    return (
      <DefaultItem id={ id } typeSlug="media" placeholder={ placeholder }>
        { (medium) => {
          const { error } = this.state;
          const { aspectRatio, width } = this.props;

          const mediumSizes = path(
            ['media_details', 'sizes'],
            site.objectToResponse(medium).offline()
          );

          if (!mediumSizes || error) {
            return placeholder;
          }

          const { alt_text: altText, title: { rendered } } = medium;

          const filteredSizes
            = filterSizesByAspectRatio(mediumSizes, aspectRatio);

          /*
          * Image source url selected based on provided prop width
          * out of filtered list of sources based on aspect ratio
          */
          const sizeUrl = getImageUrlByWidth(width, filteredSizes);

          const srcSet = values(map(
            ({ width: srcWidth, source_url: sourceUrl }) =>
              `${sourceUrl} ${srcWidth}w`,
            filteredSizes
          )).join(', ');

          if (!sizeUrl) {
            printError('There is no image with supplied width');
            return null;
          }

          return (
            <Image
              alt={ altText }
              onError={ this.handleError }
              src={ sizeUrl }
              /* There's no point choosing between different sizes when
               we're offline, so skip `srcset` api
               */
              srcSet={ site.isOnline() && srcSet }
              title={ rendered }
              { ...omit(append('dispatch', keys(propTypes)), this.props) }
            />
          );
        } }
      </DefaultItem>
    );
  };
}

MediaImage.propTypes = propTypes;
MediaImage.defaultProps = defaultProps;

export default withSite(MediaImage);
