/* eslint-disable no-plusplus */
import React, { useEffect, useMemo, useState, useRef, useImperativeHandle, forwardRef, useContext } from 'react';
import clsx from 'clsx';
import Loading from '../loading';
import Column from './PickerColumn';
import useRefs from '../hooks/use-refs';
import useEventListener from '../hooks/use-event-listener';
import { unitToPx, preventDefault, extend } from '../utils';
import { BORDER_UNSET_TOP_BOTTOM } from '../utils/constant';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';
import { raf } from '../utils/raf';

function PickerInner(props, ref) {
  var _useContext = useContext(ConfigProviderContext),
      prefixCls = _useContext.prefixCls,
      createNamespace = _useContext.createNamespace,
      locale = _useContext.locale;

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

  var _useRefs = useRefs(),
      refs = _useRefs[0],
      setRefs = _useRefs[1],
      resetRefs = _useRefs[2];

  var _useState = useState([]),
      formattedColumns = _useState[0],
      setFormattedColumns = _useState[1];

  var _extend = extend({
    // compatible with valueKey prop
    text: 'text',
    values: 'values',
    children: 'children'
  }, props.columnsFieldNames),
      textKey = _extend.text,
      valuesKey = _extend.values,
      childrenKey = _extend.children;

  var wrapper = useRef(null);
  var itemHeight = useMemo(function () {
    return unitToPx(props.itemHeight);
  }, [props.itemHeight]);
  var dataType = useMemo(function () {
    var columns = props.columns;
    var firstColumn = columns[0] || {};

    if (typeof firstColumn === 'object') {
      if (childrenKey in firstColumn) {
        return 'cascade';
      }

      if (valuesKey in firstColumn) {
        return 'object';
      }
    }

    return 'plain'; // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [props.columns]);

  var formatCascade = function formatCascade() {
    var _cursor;

    var formatted = [];
    var cursor = (_cursor = {}, _cursor[childrenKey] = props.columns, _cursor);

    while (cursor && cursor[childrenKey]) {
      var _cursor$defaultIndex, _formatted$push;

      var children = cursor[childrenKey];
      var defaultIndex = (_cursor$defaultIndex = cursor.defaultIndex) != null ? _cursor$defaultIndex : +props.defaultIndex;

      while (children[defaultIndex] && children[defaultIndex].disabled) {
        if (defaultIndex < children.length - 1) {
          defaultIndex++;
        } else {
          defaultIndex = 0;
          break;
        }
      }

      formatted.push((_formatted$push = {}, _formatted$push[valuesKey] = cursor[childrenKey], _formatted$push.className = cursor.className, _formatted$push.defaultIndex = defaultIndex, _formatted$push));
      cursor = children[defaultIndex];
    }

    setFormattedColumns(formatted);
  };

  var format = function format() {
    var columns = props.columns;

    if (dataType === 'plain') {
      var _ref2;

      setFormattedColumns([(_ref2 = {}, _ref2[valuesKey] = columns, _ref2)]);
    } else if (dataType === 'cascade') {
      formatCascade();
    } else {
      setFormattedColumns(columns);
    }
  }; // get indexes of all columns


  var getIndexes = function getIndexes() {
    return refs.map(function (_ref) {
      return _ref.state.index;
    });
  }; // set options of column by index


  var setColumnValues = function setColumnValues(index, options) {
    var column = refs[index];

    if (column) {
      column.setOptions(options);
    }
  };

  var onCascadeChange = function onCascadeChange(columnIndex) {
    var _cursor2;

    var cursor = (_cursor2 = {}, _cursor2[childrenKey] = props.columns, _cursor2);
    var indexes = getIndexes();

    for (var i = 0; i <= columnIndex; i += 1) {
      cursor = cursor[childrenKey][indexes[i]];
    }

    if (cursor && cursor[childrenKey]) {
      while (cursor && cursor[childrenKey]) {
        var _cursor$childrenKey;

        columnIndex += 1;
        setColumnValues(columnIndex, cursor[childrenKey]);
        cursor = (_cursor$childrenKey = cursor[childrenKey]) == null ? void 0 : _cursor$childrenKey[cursor.defaultIndex || 0];
      }
    } else {
      // Clean unsafe data children value
      // https://github.com/3lang3/react-vant/issues/378
      refs.forEach(function (column, i) {
        if (i > columnIndex && columnIndex < refs.length) {
          column.setOptions([]);
        }
      });
    }
  }; // get column instance by index


  var getChild = function getChild(index) {
    return refs[index];
  }; // get column value by index


  var getColumnValue = function getColumnValue(index) {
    var column = getChild(index);
    return column.getValue();
  }; // set column value by index


  var setColumnValue = function setColumnValue(index, value) {
    var column = getChild(index);

    if (column) {
      column.setValue(value);

      if (dataType === 'cascade') {
        onCascadeChange(index);
      }
    }
  }; // get column option index by column index


  var getColumnIndex = function getColumnIndex(index) {
    var column = getChild(index);
    return column.state.index;
  }; // set column option index by column index


  var setColumnIndex = function setColumnIndex(columnIndex, optionIndex) {
    var column = getChild(columnIndex);

    if (column) {
      column.setIndex(optionIndex);

      if (dataType === 'cascade') {
        onCascadeChange(columnIndex);
      }
    }
  }; // get options of column by index


  var getColumnValues = function getColumnValues(index) {
    var column = getChild(index);
    return column && column.getValue();
  }; // get values of all columns


  var getValues = function getValues() {
    return refs.map(function (_ref) {
      return _ref.getValue();
    });
  }; // set values of all columns


  var setValues = function setValues(values) {
    values.forEach(function (value, index) {
      setColumnValue(index, value);
    });
  }; // set indexes of all columns


  var setIndexes = function setIndexes(indexes) {
    indexes.forEach(function (optionIndex, columnIndex) {
      setColumnIndex(columnIndex, optionIndex);
    });
  };

  var _onChange = function onChange(columnIndex) {
    if (dataType === 'cascade') {
      onCascadeChange(columnIndex);
    }

    if (props.onChange) {
      if (dataType === 'plain') {
        props.onChange(getColumnValue(0), getColumnIndex(0));
      } else {
        props.onChange(getValues(), columnIndex);
      }
    }
  };

  var confirm = function confirm() {
    refs.forEach(function (_ref) {
      return _ref.stopMomentum();
    });

    if (props.onConfirm) {
      raf(function () {
        if (dataType === 'plain') {
          props.onConfirm(getColumnValue(0), getColumnIndex(0));
        } else {
          props.onConfirm(getValues(), getIndexes());
        }
      });
    }
  };

  var cancel = function cancel() {
    if (dataType === 'plain') {
      props.onCancel == null ? void 0 : props.onCancel(getColumnValue(0), getColumnIndex(0));
    } else {
      props.onCancel == null ? void 0 : props.onCancel(getValues(), getIndexes());
    }
  };

  var renderTitle = function renderTitle() {
    if (props.title) {
      return /*#__PURE__*/React.createElement("div", {
        className: clsx(bem('title'), 'rv-ellipsis')
      }, props.title);
    }

    return null;
  };

  var renderCancel = function renderCancel() {
    var text = props.cancelButtonText || locale.cancel;
    return /*#__PURE__*/React.createElement("button", {
      type: "button",
      className: clsx(bem('cancel')),
      onClick: cancel
    }, text);
  };

  var renderConfirm = function renderConfirm() {
    var text = props.confirmButtonText || locale.confirm;
    return /*#__PURE__*/React.createElement("button", {
      type: "button",
      className: clsx(bem('confirm')),
      onClick: confirm
    }, text);
  };

  var renderToolbar = function renderToolbar() {
    if (props.showToolbar) {
      return /*#__PURE__*/React.createElement("div", {
        className: clsx(bem('toolbar'))
      }, props.toolbar || /*#__PURE__*/React.createElement(React.Fragment, null, renderCancel(), renderTitle(), renderConfirm()));
    }

    return null;
  };

  var renderColumnItems = function renderColumnItems() {
    return formattedColumns.map(function (item, columnIndex) {
      var _item$defaultIndex;

      return /*#__PURE__*/React.createElement(Column // eslint-disable-next-line react/no-array-index-key
      , {
        // eslint-disable-next-line react/no-array-index-key
        key: columnIndex,
        optionRender: props.optionRender,
        ref: setRefs(columnIndex),
        textKey: textKey,
        readonly: props.readonly,
        className: item.className,
        itemHeight: itemHeight,
        defaultIndex: (_item$defaultIndex = item.defaultIndex) != null ? _item$defaultIndex : +props.defaultIndex,
        swipeDuration: props.swipeDuration,
        visibleItemCount: props.visibleItemCount,
        initialOptions: item[valuesKey],
        onChange: function onChange() {
          _onChange(columnIndex);
        }
      });
    });
  };

  var renderColumns = function renderColumns() {
    var wrapHeight = itemHeight * props.visibleItemCount;
    var frameStyle = {
      height: itemHeight + "px"
    };
    var columnsStyle = {
      height: wrapHeight + "px"
    };
    var maskStyle = {
      backgroundSize: "100% " + (wrapHeight - itemHeight) / 2 + "px"
    };
    return /*#__PURE__*/React.createElement("div", {
      ref: wrapper,
      className: clsx(bem('columns')),
      style: columnsStyle
    }, renderColumnItems(), /*#__PURE__*/React.createElement("div", {
      className: clsx(bem('mask')),
      style: maskStyle
    }), /*#__PURE__*/React.createElement("div", {
      className: clsx(BORDER_UNSET_TOP_BOTTOM, bem('frame')),
      style: frameStyle
    }));
  };

  useEffect(function () {
    if (JSON.stringify(props.columns) !== JSON.stringify(formattedColumns)) {
      resetRefs();
      format();
    } // eslint-disable-next-line react-hooks/exhaustive-deps

  }, [props.columns]);
  useEventListener('touchmove', preventDefault, {
    target: wrapper.current
  });
  useImperativeHandle(ref, function () {
    return {
      confirm: confirm,
      getValues: getValues,
      setValues: setValues,
      getIndexes: getIndexes,
      setIndexes: setIndexes,
      getColumnIndex: getColumnIndex,
      setColumnIndex: setColumnIndex,
      getColumnValue: getColumnValue,
      setColumnValue: setColumnValue,
      getColumnValues: getColumnValues,
      setColumnValues: setColumnValues
    };
  });
  return /*#__PURE__*/React.createElement("div", {
    className: clsx(bem(), props.className)
  }, props.toolbarPosition === 'top' ? renderToolbar() : null, props.loading ? /*#__PURE__*/React.createElement(Loading, {
    className: clsx(bem('loading'))
  }) : null, props.columnsTop, renderColumns(), props.columnsBottom, props.toolbarPosition === 'bottom' ? renderToolbar() : null);
}

var Picker = /*#__PURE__*/forwardRef(PickerInner);
Picker.defaultProps = {
  itemHeight: 44,
  visibleItemCount: 5,
  swipeDuration: 1000,
  defaultIndex: 0,
  showToolbar: true,
  toolbarPosition: 'top'
};
export default Picker;