import React, { useEffect, useRef } from "react";
import classNames from "classnames";
import { DateChangeContext } from "../calendar/DateProps";
import { useConfig } from "../_util/config-context";
import { List } from "../list";

const SCROLL_OFFSET = 80;
const SCROLL_DURATION = 120;

export interface SelectProps {
  /**
   * 当前选择的值
   */
  value: number;

  /**
   * 起始值
   */
  from?: number;

  /**
   * 结束值
   */
  to: number;

  /**
   * 步长
   */
  step?: number;

  /**
   * 禁选范围
   */
  disabledValues?: number[];

  /**
   * 变化回调
   */
  onChange: (value: number, context: DateChangeContext) => void;
}

/**
 * 滚动到指定元素
 */
function scrollTo(element: HTMLElement, to: number, duration: number): void {
  if (duration <= 0) {
    element.scrollTop = to;
    return;
  }
  const difference = to - element.scrollTop;
  const perTick = (difference / duration) * 10;

  requestAnimationFrame(() => {
    element.scrollTop += perTick;
    if (element.scrollTop === to) return;
    scrollTo(element, to, duration - 10);
  });
}

export function TimeSelect({
  value,
  from = 0,
  to,
  step = 1,
  disabledValues = [],
  onChange = () => null,
}: SelectProps) {
  const { classPrefix } = useConfig();
  const selectRef = useRef(null);

  useEffect(() => {
    scrollToSelected(0);
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    scrollToSelected(SCROLL_DURATION);
  }, [value, from, to, step]); // eslint-disable-line react-hooks/exhaustive-deps

  /**
   * 滚动到当前选择元素
   */
  function scrollToSelected(duration: number): void {
    const element = selectRef.current;

    const index = Math.floor(value / step);
    const topOption = element.children[index] as HTMLElement;
    const to = topOption.offsetTop - element.offsetTop - SCROLL_OFFSET;

    scrollTo(element, to, duration);
  }

  /**
   * 根据范围生成列表
   */
  function genRangeList(): number[] {
    return Array(Math.floor((to - from + 1) / step))
      .fill(0)
      .map((_, i) => i * step + from);
  }

  function handleSelect(event: React.MouseEvent, value: number): void {
    event.stopPropagation();
    onChange(value, { event });
  }

  return (
    <List
      ref={selectRef}
      type="option"
      className={`${classPrefix}-list--calendar-time`}
    >
      {genRangeList().map(item => {
        const disabled = disabledValues.includes(item);
        return (
          <List.Item
            key={item}
            className={classNames({
              "is-disabled": disabled,
              "is-selected": !disabled && item === value,
            })}
            onClick={e => !disabled && handleSelect(e, item)}
          >
            <div className={`${classPrefix}-list__item`}>
              {item > 9 ? `${item}` : `0${item}`}
            </div>
          </List.Item>
        );
      })}
    </List>
  );
}

TimeSelect.displayName = "TimeSelect";
