var _excluded = ["count", "touchable", "onChange"];

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

/* eslint-disable no-nested-ternary */
import React, { useRef, useContext, useMemo } from 'react';
import { Star, StarO } from '@react-vant/icons';
import clsx from 'clsx';
import { addUnit, preventDefault } from '../utils';
import useTouch from '../hooks/use-touch';
import useRefs from '../hooks/use-refs';
import useMergedState from '../hooks/use-merged-state';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';
import useEventListener from '../hooks/use-event-listener';

function getRateStatus(value, index, allowHalf, readonly) {
  if (value >= index) {
    return {
      status: 'full',
      value: 1
    };
  }

  if (value + 0.5 >= index && allowHalf && !readonly) {
    return {
      status: 'half',
      value: 0.5
    };
  }

  if (value + 1 >= index && allowHalf && readonly) {
    var cardinal = Math.pow(10, 10);
    return {
      status: 'half',
      value: Math.round((value - index + 1) * cardinal) / cardinal
    };
  }

  return {
    status: 'void',
    value: 0
  };
}

var Rate = function Rate(_ref) {
  var count = _ref.count,
      touchable = _ref.touchable,
      onChange = _ref.onChange,
      props = _objectWithoutPropertiesLoose(_ref, _excluded);

  var _useContext = useContext(ConfigProviderContext),
      prefixCls = _useContext.prefixCls,
      createNamespace = _useContext.createNamespace;

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

  var _useMergedState = useMergedState({
    value: props.value,
    defaultValue: props.defaultValue
  }),
      value = _useMergedState[0],
      setValue = _useMergedState[1];

  var root = useRef(null);
  var touch = useTouch(true);

  var _useRefs = useRefs(),
      itemRefs = _useRefs[0],
      setItemRefs = _useRefs[1];

  var untouchable = function untouchable() {
    return props.readonly || props.disabled || !touchable;
  };

  var list = useMemo(function () {
    return Array(count).fill('').map(function (_, i) {
      return getRateStatus(value, i + 1, props.allowHalf, props.readonly);
    });
  }, [count, value, props.allowHalf, props.readonly]);
  var ranges = useRef();

  var updateRanges = function updateRanges() {
    var rects = itemRefs.map(function (item) {
      return item.getBoundingClientRect();
    });
    ranges.current = [];
    rects.forEach(function (rect, index) {
      if (props.allowHalf) {
        ranges.current.push({
          score: index + 0.5,
          left: rect.left
        }, {
          score: index + 1,
          left: rect.left + rect.width / 2
        });
      } else {
        ranges.current.push({
          score: index + 1,
          left: rect.left
        });
      }
    });
  };

  var getScoreByPosition = function getScoreByPosition(x) {
    // eslint-disable-next-line no-plusplus
    for (var i = ranges.current.length - 1; i > 0; i--) {
      if (x > ranges.current[i].left) {
        return ranges.current[i].score;
      }
    }

    return props.allowHalf ? 0.5 : 1;
  };

  var select = function select(index) {
    if (!props.disabled && !props.readonly && index !== value) {
      setValue(index);
      onChange == null ? void 0 : onChange(index);
    }
  };

  var onTouchStart = function onTouchStart(event) {
    if (untouchable()) {
      return;
    }

    touch.start(event.nativeEvent);
    updateRanges();
  };

  var onTouchMove = function onTouchMove(event) {
    if (untouchable()) {
      return;
    }

    touch.move(event);

    if (touch.isHorizontal()) {
      var clientX = event.touches[0].clientX;
      preventDefault(event);
      select(getScoreByPosition(clientX));
    }
  };

  var renderStar = function renderStar(item, index) {
    var icon = props.icon,
        size = props.size,
        color = props.color,
        gutter = props.gutter,
        voidIcon = props.voidIcon,
        disabled = props.disabled,
        voidColor = props.voidColor,
        allowHalf = props.allowHalf,
        disabledColor = props.disabledColor;
    var score = index + 1;
    var isFull = item.status === 'full';
    var isVoid = item.status === 'void';
    var renderHalf = allowHalf && item.value > 0 && item.value < 1;
    var style;

    if (gutter && score !== +count) {
      style = {
        paddingRight: addUnit(gutter)
      };
    }

    var onClickItem = function onClickItem(event) {
      updateRanges();
      select(allowHalf ? getScoreByPosition(event.clientX) : score);
    };

    return /*#__PURE__*/React.createElement("div", {
      key: index,
      ref: setItemRefs(index),
      role: "radio",
      style: style,
      className: clsx(bem('item')),
      tabIndex: 0,
      "aria-setsize": parseInt(count == null ? void 0 : count.toString(), 10),
      "aria-posinset": score,
      "aria-checked": !isVoid,
      onClick: onClickItem
    }, /*#__PURE__*/React.cloneElement(isFull ? icon : voidIcon, {
      className: clsx(bem('icon', {
        disabled: disabled,
        full: isFull
      })),
      style: {
        color: disabled ? disabledColor : isFull ? color : voidColor,
        fontSize: size
      }
    }), renderHalf && /*#__PURE__*/React.createElement("div", {
      className: clsx(bem('icon', ['half'])),
      style: {
        width: item.value + "em"
      }
    }, /*#__PURE__*/React.cloneElement(isVoid ? voidIcon : icon, {
      className: clsx(bem('icon', [{
        disabled: disabled,
        full: !isVoid
      }])),
      style: {
        color: disabled ? disabledColor : isVoid ? voidColor : color,
        fontSize: size
      }
    })));
  };

  useEventListener('touchmove', onTouchMove, {
    target: root.current,
    depends: [touch.deltaY]
  });
  return /*#__PURE__*/React.createElement("div", {
    ref: root,
    role: "radiogroup",
    className: clsx(bem({
      readonly: props.readonly,
      disabled: props.disabled
    })),
    tabIndex: 0,
    onTouchStart: onTouchStart
  }, list.map(renderStar));
};

Rate.defaultProps = {
  size: 20,
  count: 5,
  gutter: 4,
  icon: /*#__PURE__*/React.createElement(Star, null),
  voidIcon: /*#__PURE__*/React.createElement(StarO, null),
  touchable: true
};
export default Rate;