import PropTypes from 'prop-types';
import { equals, pick } from 'ramda';
import { Component } from 'react';
import { connect } from 'react-redux';

import { withSite } from '../../addons/Site';
import { printError } from '../../lib';

/* Interface */
export const propTypes = {
  /** Function to call with loaded post or term. */
  children: PropTypes.func,

  /** ID of post or term to load. */
  id: PropTypes.number,

  /**
   * Loaded post or term.
   * @private
   */
  item: PropTypes.object,

  /** Slug of post or term to load. */
  itemSlug: PropTypes.string,

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

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

  /** Slug for post type or taxonomy from which posts or terms are drawn. */
  typeSlug: PropTypes.string.isRequired,
};

/* Defaults */
const defaultProps = {
  children: () => null,
  placeholder: null,
};

/**
 * Loads an item from StoryShare
 * Should be given a functional child which will be passed the loaded item when
 * it becomes available.
 * @returns {Object} component
 */
export class Item extends Component {
  /**
   * Loads the post when the component mounts.
   * @returns {void}
   */
  componentDidMount = () => this.fetchData();

  /**
   * Loads the post when the component updates.
   * @param {Object} prevProps - Previous props values.
   * @returns {void}
   */
  componentDidUpdate = (prevProps) => {
    const picker = pick(['id', 'itemSlug', 'typeSlug']);
    if (!equals(picker(this.props), picker(prevProps))) {
      this.fetchData();
    }
  };

  /**
   * Requests data from the StoryShare instance.
   * @returns {void}
   */
  fetchData = () => {
    const { id, itemSlug, site, typeSlug } = this.props;

    if (id && itemSlug) {
      printError(
        'Trying to find <Item> with both ID and slug: is this what you meant?'
      );
    }

    if (id) {
      site.req(`${typeSlug}/${id}`)
        .read();
    }

    if (itemSlug) {
      site.req(`${typeSlug}`)
        .addParam('slug', itemSlug)
        .read();
    }
  };

  render = () => {
    const { children, item, placeholder } = this.props;

    if (!item) {
      return placeholder;
    }

    return children(item);
  };
}

Item.defaultProps = defaultProps;
Item.propTypes = propTypes;

export const mapStateToProps = (_, { id, itemSlug, site, typeSlug }) => {
  if (id) {
    return { item: site.getObjectByRoute(`${typeSlug}/${id}`) };
  }

  if (itemSlug) {
    return { item: site.getObjectBySlug(itemSlug, typeSlug) };
  }

  return { };
};

// n.b. ordering: mapStateToProps needs site
export default withSite(connect(mapStateToProps)(Item));
