import React, { useRef, forwardRef, useImperativeHandle, isValidElement, useContext } from 'react';
import clsx from 'clsx';
import Loading from '../loading';
import { getRect } from '../hooks/use-rect';
import useScrollParent from '../hooks/use-scroll-parent';
import useEventListener from '../hooks/use-event-listener';
import { isHidden } from '../utils';
import { useSetState, useUpdateEffect } from '../hooks';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';

function _empty() {}

var List = /*#__PURE__*/forwardRef(function (props, ref) {
  var _useContext = useContext(ConfigProviderContext),
      prefixCls = _useContext.prefixCls,
      createNamespace = _useContext.createNamespace,
      locale = _useContext.locale;

  var _createNamespace = createNamespace('list', prefixCls),
      bem = _createNamespace[0];

  var _useSetState = useSetState({
    loading: props.loading,
    error: props.error
  }),
      state = _useSetState[0],
      updateState = _useSetState[1];

  var root = useRef();
  var scrollParent = useRef(null);
  var placeholder = useRef();
  scrollParent.current = useScrollParent(root); // 判断是否需要加载

  var check = _async(function () {
    if (!props.onLoad) return;

    if (state.loading || props.finished || state.error) {
      return;
    }

    var offset = props.offset,
        direction = props.direction;
    var scrollParentRect = getRect(scrollParent.current);

    if (!scrollParentRect.height || isHidden(root.current)) {
      return;
    }

    var isReachEdge = false;
    var placeholderRect = getRect(placeholder.current);

    if (direction === 'up') {
      isReachEdge = scrollParentRect.top - placeholderRect.top <= offset;
    } else {
      isReachEdge = placeholderRect.bottom - scrollParentRect.bottom <= offset;
    }

    return _invokeIgnored(function () {
      if (isReachEdge) {
        return _continueIgnored(_catch(function () {
          updateState({
            loading: true
          });
          return _invoke(function () {
            if (props.onLoad) return _awaitIgnored(props.onLoad());
          }, function () {
            updateState({
              loading: false
            });
          });
        }, function (error) {
          // eslint-disable-next-line no-console
          console.warn('onLoad error:', error);
          updateState({
            loading: false,
            error: true
          });
        }));
      }
    });
  });

  var renderFinishedText = function renderFinishedText() {
    if (props.finished && props.finishedText) {
      return /*#__PURE__*/React.createElement("div", {
        className: clsx(bem('finished-text'))
      }, props.finishedText);
    }

    return null;
  };

  var clickErrorText = function clickErrorText() {
    updateState({
      error: false
    });
    check();
  };

  var renderErrorText = function renderErrorText() {
    if (state.error && props.errorText) {
      return /*#__PURE__*/React.createElement("div", {
        className: clsx(bem('error-text')),
        onClick: clickErrorText
      }, props.errorText);
    }

    return null;
  };

  var renderLoading = function renderLoading() {
    if (state.loading && !props.finished) {
      return /*#__PURE__*/React.createElement("div", {
        className: clsx(bem('loading'))
      }, /*#__PURE__*/isValidElement(props.loadingText) ? props.loadingText : /*#__PURE__*/React.createElement(Loading, {
        className: clsx(bem('loading-icon')),
        size: 16
      }, props.loadingText || locale.loading));
    }

    return null;
  };

  useUpdateEffect(function () {
    if (props.autoCheck) {
      check();
    }
  }, [state.loading, props.finished, props.error]);
  useUpdateEffect(function () {
    updateState({
      loading: props.loading,
      error: props.error
    });
  }, [props.loading, props.error]);
  useUpdateEffect(function () {
    if (scrollParent.current && props.immediateCheck) {
      check();
    }
  }, [scrollParent.current]);
  useEventListener('scroll', check, {
    target: scrollParent.current,
    depends: [state.loading, props.finished, state.error]
  });
  useImperativeHandle(ref, function () {
    return {
      check: check,
      state: state
    };
  });
  var Placeholder = /*#__PURE__*/React.createElement("div", {
    ref: placeholder,
    className: clsx(bem('placeholder'))
  });
  return /*#__PURE__*/React.createElement("div", {
    ref: root,
    role: "feed",
    className: clsx(bem(), props.className),
    style: props.style,
    "aria-busy": state.loading
  }, props.direction === 'down' ? props.children : Placeholder, renderLoading(), renderFinishedText(), renderErrorText(), props.direction === 'up' ? props.children : Placeholder);
});

function _awaitIgnored(value, direct) {
  if (!direct) {
    return value && value.then ? value.then(_empty) : Promise.resolve();
  }
}

function _invoke(body, then) {
  var result = body();

  if (result && result.then) {
    return result.then(then);
  }

  return then(result);
}

function _catch(body, recover) {
  try {
    var result = body();
  } catch (e) {
    return recover(e);
  }

  if (result && result.then) {
    return result.then(void 0, recover);
  }

  return result;
}

function _continueIgnored(value) {
  if (value && value.then) {
    return value.then(_empty);
  }
}

function _invokeIgnored(body) {
  var result = body();

  if (result && result.then) {
    return result.then(_empty);
  }
}

function _async(f) {
  return function () {
    for (var args = [], i = 0; i < arguments.length; i++) {
      args[i] = arguments[i];
    }

    try {
      return Promise.resolve(f.apply(this, args));
    } catch (e) {
      return Promise.reject(e);
    }
  };
}

List.defaultProps = {
  offset: 300,
  direction: 'down',
  immediateCheck: true,
  autoCheck: true
};
export default List;