import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import Loader from '../loader';
import Error from '../error';
import { fetchData } from '../../utils/fetch';
import { ERROR, INIT, LOADING } from '../../../redux/constants';

function Fetcher(props) {
  const location = useLocation();

  useEffect(() => fetchData(props.action), [props.action, location.key]);
  // Loading
  if ([INIT, LOADING].includes(props.status)) return props.renderLoader();
  // Error
  if (props.status === ERROR) {
    const result = props.renderError(props.error);
    if (result !== null) return result;
  }
  // Empty Data
  if (
    (Array.isArray(props.data) && props.data.length === 0) ||
    (Object.entries(props.data).length === 0 && props.data.constructor === Object)
  ) {
    const result = props.renderEmpty();
    if (result !== null) return result;
  }
  // Good Condition
  return props.children(props.data);
}

Fetcher.propTypes = {
  action: PropTypes.func.isRequired,
  stateSelector: PropTypes.func.isRequired,
  status: PropTypes.string.isRequired,
  data: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]).isRequired,
  renderLoader: PropTypes.func.isRequired,
  renderEmpty: PropTypes.func.isRequired,
  renderError: PropTypes.func.isRequired,
  error: PropTypes.oneOfType(PropTypes.string, PropTypes.object),
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node), PropTypes.func])
};

Fetcher.defaultProps = {
  renderLoader: () => <Loader />,
  renderEmpty: () => null,
  // eslint-disable-next-line react/display-name
  renderError: error => <Error errorCode={error.status} errorData={error.data} />
};

function mapStateToProps(state, { stateSelector }) {
  return {
    status: stateSelector(state).status,
    error: stateSelector(state).error,
    data: stateSelector(state).data
  };
}

function mapDispatchToProps(dispatch, { action }) {
  return bindActionCreators({ action }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Fetcher);
