import classNames from "classnames";
import React, { useState } from "react";
import { ControlledProps, useDefaultValue } from "../form/controlled";
import { Icon } from "../icon";
import { callBoth, useConfig } from "../util";
import { StyledProps } from "../_type";
import { injectValue } from "../_util/inject-value";
import { KeyMap } from "../_util/key-map";

export interface RateCharacterProps {
  /**
   * 序号
   */
  index: number;

  /**
   * 是否被全选
   */
  full: boolean;

  /**
   * 是否被半选
   */
  half: boolean;
}

export interface RateProps extends ControlledProps<number>, StyledProps {
  /**
   * 字符数
   * @default 5
   */
  count?: number;

  /**
   * 是否启用半选
   * @default false
   */
  allowHalf?: boolean;

  /**
   * 是否启用再次点击当前值后清空
   * @default true
   */
  allowClear?: boolean;

  /**
   * 是否为只读形式
   * @default false
   */
  readonly?: boolean;

  /**
   * 主题
   * @default "default"
   */
  theme?: "default" | "primary";

  /**
   * 尺寸
   * @default "m"
   */
  size?: "m" | "l";

  /**
   * 自定义字符
   *
   * `[未点亮字符, 点亮字符]`
   */
  character?:
    | [React.ReactNode, React.ReactNode]
    | ((props: RateCharacterProps) => [React.ReactNode, React.ReactNode]);
}

const defaultCharacter = size => [
  <Icon type="star" className={size === "l" ? "size-l" : ""} />,
  <Icon type="star-warning" className={size === "l" ? "size-l" : ""} />,
];
const primaryCharacter = size => [
  <Icon type="star" className={size === "l" ? "size-l" : ""} />,
  <Icon type="star-primary" className={size === "l" ? "size-l" : ""} />,
];

export const Rate = React.forwardRef(function Rate(
  props: RateProps,
  ref: React.Ref<HTMLDivElement>
) {
  const { classPrefix } = useConfig();
  const {
    value,
    onChange,
    count = 5,
    allowClear = true,
    allowHalf,
    readonly,
    theme,
    size,
    character = theme === "primary"
      ? primaryCharacter(size)
      : defaultCharacter(size),
    className,
    ...restProps
  } = useDefaultValue(props, 0);

  // 内部
  const innerValue = Math.round(value * 2);
  const [hoverValue, setHoverValue] = useState(-1);

  const current = hoverValue >= 0 ? hoverValue : innerValue;

  function handleClick(event: React.MouseEvent, value: number) {
    if (readonly) {
      return;
    }

    setHoverValue(value);
    if (allowClear && innerValue === value) {
      onChange(0, { event });
      setHoverValue(-1);
      return;
    }
    onChange(Number((value / 2).toFixed(1)), {
      event,
    });
  }

  function handleMouseEnter(value: number) {
    if (readonly) {
      return;
    }
    setHoverValue(value);
  }

  function handleMouseLeave() {
    setHoverValue(-1);
  }

  function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
    if (readonly) {
      return;
    }
    switch (event.key) {
      case KeyMap.Left:
        setHoverValue(-1);
        if (innerValue >= 1) {
          onChange(
            Number(((innerValue - (allowHalf ? 1 : 2)) / 2).toFixed(1)),
            { event }
          );
        }
        break;
      case KeyMap.Right:
        setHoverValue(-1);
        if (innerValue < count * 2) {
          onChange(
            Number(((innerValue + (allowHalf ? 1 : 2)) / 2).toFixed(1)),
            { event }
          );
        }
        break;
      case KeyMap.Backspace:
        setHoverValue(-1);
        onChange(0, { event });
        break;
    }
  }

  return (
    <div
      ref={ref}
      className={classNames(`${classPrefix}-rate`, className)}
      {...restProps}
      tabIndex={0}
      role="radiogroup"
      onMouseLeave={callBoth((restProps as any).onMouseLeave, handleMouseLeave)}
      onKeyDown={callBoth((restProps as any).onKeyDown, handleKeyDown)}
    >
      {Array(count)
        .fill(null)
        .map((_, index) => {
          const itemValue = index * 2 + 2;
          const half = itemValue === current + 1 && current % 2 > 0;
          const full = itemValue <= current;
          const [inactive, active] = injectValue(character)({
            index,
            half,
            full,
          });
          return (
            <div
              className={classNames(`${classPrefix}-rate__item`)}
              key={index}
            >
              {allowHalf && (
                <div
                  className={`${classPrefix}-rate__item-up`}
                  onClick={event => handleClick(event, itemValue - 1)}
                  onMouseEnter={() => handleMouseEnter(itemValue - 1)}
                >
                  {!(full || half) ? inactive : active}
                </div>
              )}
              <div
                className={`${classPrefix}-rate__item-down`}
                onClick={event => handleClick(event, itemValue)}
                onMouseEnter={() => handleMouseEnter(itemValue)}
              >
                {!full ? inactive : active}
              </div>
            </div>
          );
        })}
    </div>
  );
});
