import React, { useEffect, useRef, useState } from "react";
import { LeftOutlined, RightOutlined } from "@easyv/react-icons";
import { Input } from "antd";
import classNames from "classnames";
import { interpolateNumber, transition } from "d3";
import { SortableContainer, SortableElement } from "react-sortable-hoc";
import Tabs from "../tabs";
import ContextMenu from "./ContextMenu";
import styles from "./SortableTabs.less";

const { TabPane } = Tabs;

const SortableItem = SortableElement(
  ({
    isMultiple,
    isEditName,
    value,
    activeKey,
    isEdit,
    onActiveKeyChange,
    handleRightClick,
    selectedKeys,
    onSelectedKeysChange,
    onEditName,
    extraObj,
    liIndex,
  }) => {
    const { handleChangeName } = extraObj;
    const [editText, setEditText] = useState(value.props.tab);
    useEffect(() => {
      isEdit && setEditText(value.props.tab);
    }, [value, isEdit]);
    const handleClick = (e) => {
      if (isMultiple) {
        // 多选时保持选中状态
        e.shiftKey
          ? onSelectedKeysChange([...new Set([...selectedKeys, value.key])])
          : onSelectedKeysChange([value.key]);
      }
      e.target.scrollIntoView({ behavior: "smooth" });
      onActiveKeyChange(value.key);
    };

    const handleEditName = (e) => {
      const newValue = e.target.value.trim();
      if (newValue && newValue !== value.props.tab) {
        const update = [{ paths: [], value: newValue, key: "name" }];
        handleChangeName && handleChangeName(liIndex, update);
      }
      onEditName(null);
      e.target.scrollIntoView({ behavior: "smooth" });
      onActiveKeyChange(value.key);
      isMultiple && onSelectedKeysChange([value.key]);
    };

    return (
      <li
        id={value.key}
        className={classNames(styles.item, {
          [styles.active]: activeKey === value.key || selectedKeys.includes(value.key),
          [styles.edit]: isEdit,
        })}
        onClick={handleClick}
        onDoubleClick={() => {
          if (!isEditName) {
            return;
          }
          onEditName(value.key);
        }}
        onContextMenu={(e) => handleRightClick(e, value)}
      >
        {isEdit ? (
          <Input
            autoFocus
            value={editText}
            className={styles.liInput}
            style={{ background: "transparent", color: "#fff" }}
            maxLength={10}
            onChange={(e) => {
              const newValue = e.target.value.trim();
              // newValue && setEditText(newValue);
              setEditText(newValue);
            }}
            onPressEnter={handleEditName}
            onBlur={handleEditName}
          />
        ) : (
          value.props.tab
        )}
      </li>
    );
  },
);

const SortableList = SortableContainer(
  ({
    items,
    activeKey,
    tabsRef,
    isMultiple,
    isEditName,
    onActiveKeyChange,
    selectedKeys,
    onSelectedKeysChange,
    extraObj,
  }) => {
    const [menuItem, setMenuItem] = useState(null);
    const [editKey, setEditKey] = useState(null);

    const handleRightClick = (e, value) => {
      if (isMultiple || isEditName) {
        e.preventDefault(); // 阻止默认的右键菜单弹出
        const { key } = value;
        setMenuItem({
          x: e.clientX,
          y: e.clientY,
          chooseKey: key,
        });
      }
    };
    return (
      <>
        <ul className={styles.list} ref={tabsRef}>
          {items.map((value, index) => (
            <SortableItem
              key={`item-${value.key}`}
              index={index}
              value={value}
              isMultiple={isMultiple}
              isEditName={isEditName}
              activeKey={activeKey}
              isEdit={editKey === value.key}
              onActiveKeyChange={onActiveKeyChange}
              handleRightClick={handleRightClick}
              selectedKeys={selectedKeys}
              onSelectedKeysChange={onSelectedKeysChange}
              onEditName={setEditKey}
              extraObj={extraObj}
              liIndex={index}
            />
          ))}
        </ul>
        {menuItem ? (
          <ContextMenu
            isMultiple={isMultiple}
            menuItem={menuItem}
            setMenuItem={setMenuItem}
            selectedKeys={selectedKeys}
            activeKey={activeKey}
            extraObj={extraObj}
            onSelectedKeysChange={onSelectedKeysChange}
            onActiveKeyChange={onActiveKeyChange}
            onEditName={setEditKey}
          />
        ) : null}
      </>
    );
  },
);

export default function SortableTabs({
  isMultiple,
  isEditName,
  activeKey,
  selectedKeys,
  extraObj,
  children,
  onActiveKeyChange,
  onSort,
  onSelectedKeysChange,
}) {
  const tabsRef = useRef(null);

  const handleScroll = (direction) => (e) => {
    let scrollLeft = tabsRef.current.scrollLeft;
    let tabsWidth = tabsRef.current.getBoundingClientRect().width;

    animateScroll(tabsRef.current, scrollLeft + (direction === "left" ? -tabsWidth : tabsWidth));
  };

  const renderTabBar = (props) => {
    return (
      <div className={styles.tabBar}>
        <LeftOutlined
          className={classNames(styles.icon, styles.left)}
          onClick={handleScroll("left")}
        />
        <SortableList
          axis="x"
          distance={2}
          helperContainer={tabsRef.current}
          tabsRef={tabsRef}
          isMultiple={isMultiple}
          isEditName={isEditName}
          items={children}
          activeKey={props.activeKey}
          onActiveKeyChange={onActiveKeyChange}
          onSortEnd={onSort}
          selectedKeys={selectedKeys}
          onSelectedKeysChange={onSelectedKeysChange}
          extraObj={extraObj}
        />
        <RightOutlined
          className={classNames(styles.icon, styles.left)}
          onClick={handleScroll("right")}
        />
      </div>
    );
  };

  return (
    <Tabs className={styles.tab} renderTabBar={renderTabBar} activeKey={activeKey} animated={false}>
      {children.map((d) => (
        <TabPane tab={d.props.tab} key={d.key}>
          {d.props.children}
        </TabPane>
      ))}
    </Tabs>
  );
}

function animateScroll(obj, target) {
  transition()
    .duration(200)
    .attrTween("scrollLeft", () => {
      const i = interpolateNumber(obj.scrollLeft, target);
      return (t) => {
        obj.scrollLeft = i(t);
      };
    });
}
