import React, { useState, useEffect, useMemo, useRef, useImperativeHandle, forwardRef } from 'react';
import { Tooltip } from 'antd';
import { AutoSizer, InfiniteLoader, List } from 'react-virtualized';
import IconFont from '../../../themeComponents/IconFont';
import Box from '../../../themeComponents/CBox';
import { debounce, cloneDeep } from 'lodash';
import { computedCuurentGrid, arraySliceForX, simpleGrid } from './utils';
import './index.less';

const ScrollList = forwardRef(function InfiniteScrollLayout(props, ref) {
  const { data, itemGrid, itemHeight, threshold, isNoData, className = '', hasLoadPrev, loadPrev, prethreshold } = props;
  const infiniteRef = useRef(null);
  const loadingRef = useRef(false);
  const scrollRef = useRef(false);
  const [showBackTop, setShowBackUp] = useState(false);
  const [currentGrid, setContentGrid] = useState(computedCuurentGrid());
  let debounced = null;
  useEffect(() => {
    const bindResizeEvent = () => {
      setContentGrid(computedCuurentGrid());
    };
    window.addEventListener('resize', bindResizeEvent, false);
    return () => {
      debounced && debounced.cancel();
      window.removeEventListener('resize', bindResizeEvent, false);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const rowCount = useMemo(() => Math.floor(24 / itemGrid[currentGrid]), [itemGrid, currentGrid]);
  const renderData = useMemo(() => arraySliceForX(data, rowCount), [data, rowCount]);

  function forceUpdateGrid() {
    infiniteRef.current && infiniteRef.current._registeredChild.forceUpdateGrid();
  }

  function scrollToPosition(...args) {
    infiniteRef.current && infiniteRef.current._registeredChild.scrollToPosition(...args);
  }

  function scrollToRow(...args) {
    infiniteRef.current && infiniteRef.current._registeredChild.scrollToRow(...args);
  }

  useImperativeHandle(ref, () => ({ forceUpdateGrid, scrollToRow, scrollToPosition }));

  const loadMore = async () => {
    if (props.hasLoadMore && props.loadMore && !loadingRef.current) {
      loadingRef.current = true;
      await props.loadMore();
      loadingRef.current = false;
    }
  };

  function onListScroll(options) {
    if (hasLoadPrev && !loadingRef.current && loadPrev && options.scrollTop === 0 && scrollRef.current) {
      loadingRef.current = true;
      loadPrev().then(dataLength => {
        if (dataLength) {
          const row = Math.ceil(dataLength / rowCount);
          if (row > 0) {
            scrollToPosition(row * itemHeight);
          }
        }
        loadingRef.current = false;
      });
    }

    if (!scrollRef.current && options.scrollTop >= prethreshold) {
      scrollRef.current = true;
    }
    debounced && debounced.cancel();
    debounced = debounce(() => {
      const flag = options.scrollTop > 200;
      if (showBackTop !== flag) {
        setShowBackUp(flag);
      }
      props.onScroll && props.onScroll(options);
    }, 500);
    debounced();
  }

  function rowRender({ key, index, style }) {
    const { gutter, paddingRow, rowClass, hasLoadMore, itemClass } = props;
    let rowData = renderData[index] || [];
    let len = rowCount - rowData.length;
    if (rowData.length < rowCount) {
      for (let i = 0; i < len; i++) {
        rowData.push(null);
      }
    }

    return (
      <div key={key} style={{ ...style, padding: `0 ${paddingRow}` }} className={`row-group-part  ${rowClass}`}>
        {rowData.map((v, i) => (
          <div
            key={`${key}-${i}`}
            className={`row-item-part ${v === null && hasLoadMore ? 'row-item-placeholder' : ''} ${v !== null ? itemClass : ''}`}
            style={{
              width: `${(100 / 24) * itemGrid[currentGrid]}%`,
              height: itemHeight,
              marginRight: gutter,
              paddingBottom: gutter
            }}
          >
            {v && props.renderItem(v, i)}
          </div>
        ))}
      </div>
    );
  }

  function _isRowLoaded({ index }) {
    return !!renderData[index];
  }

  return (
    <Box className={`lm-c-infinite-scroll-layout ${isNoData ? 'infinite-scroll-empty' : ''} ${className}`}>
      <InfiniteLoader isRowLoaded={_isRowLoaded} loadMoreRows={loadMore} rowCount={renderData.length + 1} ref={infiniteRef} threshold={threshold}>
        {({ onRowsRendered, registerChild }) => {
          return (
            <AutoSizer>
              {({ width, height }) => (
                <List
                  width={width}
                  onRowsRendered={onRowsRendered}
                  ref={registerChild}
                  height={height}
                  rowCount={renderData.length}
                  rowHeight={itemHeight}
                  rowRenderer={rowRender}
                  onScroll={onListScroll}
                />
              )}
            </AutoSizer>
          );
        }}
      </InfiniteLoader>

      {props.hasBackTop && showBackTop && (
        <Tooltip title="返回顶部" placement="top">
          <div className="scoll-back-top" onClick={() => scrollToPosition(0)}>
            <IconFont type="icon-S_Arrow_MoveUp" />
          </div>
        </Tooltip>
      )}
    </Box>
  );
});

ScrollList.defaultProps = {
  itemHeight: 200,
  gutter: 20,
  itemGrid: cloneDeep(simpleGrid),
  hasLoadMore: true,
  hasLoadPrev: true,
  threshold: 5,
  prethreshold: 200,
  hasBackTop: false,
  data: []
};

export default ScrollList;
