import React, { useRef, useEffect, useState } from "react";
import classNames from "classnames";
import { TabItem } from "./TabItem";
import { Tab } from "./TabProps";
import { Button } from "../button";
import { useConfig } from "../_util/config-context";
import { useResizeObserver } from "../_util/use-resize-observer";

export interface TabBarProps {
  activeId: string;
  tabs: Tab[];
  onActive: (tab: Tab, evt: React.SyntheticEvent) => void;
  addon: React.ReactNode;
  vertical: boolean;
  maxHeight: number;
  tabBarRender: (children: JSX.Element, tab: Tab) => JSX.Element;
  style: React.CSSProperties;
  activeTabAutoScrollIntoView: boolean;
  disableTabScrolling: boolean;
}

export function TabBar({
  activeId,
  tabs,
  onActive = () => null,
  addon,
  vertical,
  maxHeight,
  tabBarRender,
  style,
  disableTabScrolling,
  activeTabAutoScrollIntoView,
}: TabBarProps) {
  const { classPrefix } = useConfig();

  // Scroll 相关
  const scrollAreaRef = useRef<HTMLDivElement>(null);
  const tabListRef = useRef<HTMLUListElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const activeItemRef = useRef<HTMLLIElement>(null);

  const [offset, setOffset] = useState<number>(0);
  const [scrolling, setScrolling] = useState<boolean>(false);

  // resize 或 tabs/addon 变化时重置滚动
  const { width } = useResizeObserver(scrollAreaRef);
  useEffect(handleScroll, [tabs, addon, width]);

  useEffect(handleActiveItemIntoView, [activeId]);

  // 设置滚动状态
  function handleScroll() {
    const scrolling = getMaxOffset() > 0;
    setScrolling(scrolling);
    // 无需滚动时重置位置
    if (!scrolling) {
      setOffset(0);
    } else {
      handleActiveItemIntoView();
    }
  }

  // 处理滚动至当前选中 TabItem
  function handleActiveItemIntoView() {
    if (!activeTabAutoScrollIntoView) {
      return;
    }
    setTimeout(() => {
      if (!scrollAreaRef.current || !activeItemRef.current) {
        return;
      }
      try {
        const scrollAreaRect = scrollAreaRef.current.getBoundingClientRect();
        const activeItemRect = activeItemRef.current.getBoundingClientRect();

        const [startPropertyName, endPropertyName] = vertical
          ? ["top", "bottom"]
          : ["left", "right"];

        const buttonProperty = vertical
          ? buttonRef.current.clientHeight
          : buttonRef.current.clientWidth;
        const startDelta =
          scrollAreaRect[startPropertyName] -
          activeItemRect[startPropertyName] +
          buttonProperty;
        const endDelta =
          activeItemRect[endPropertyName] -
          scrollAreaRect[endPropertyName] +
          buttonProperty;
        if (startDelta > 0) {
          setOffset(Math.min(0, offset + startDelta));
        } else if (endDelta > 0) {
          setOffset(Math.max(0 - getMaxOffset(), offset - endDelta));
        }
      } catch (_) {
        // ignore
      }
    }, 0);
  }

  // 获取最大滚动偏移
  function getMaxOffset() {
    // 垂直时不指定 maxHeight 不触发滚动
    if (!scrollAreaRef.current || (vertical && !maxHeight)) {
      return 0;
    }

    const propertyName = vertical ? "clientHeight" : "clientWidth";
    const scrollAreaProperty = vertical
      ? maxHeight
      : scrollAreaRef.current[propertyName];
    const tabListProperty = tabListRef.current[propertyName];
    const buttonProperty = buttonRef.current[propertyName];
    if (scrollAreaProperty >= tabListProperty) {
      return 0;
    }
    return tabListProperty - (scrollAreaProperty - buttonProperty * 2);
  }

  // 获取最大单次滚动步长
  function getStep() {
    const propertyName = vertical ? "clientHeight" : "clientWidth";
    return (
      scrollAreaRef.current[propertyName] - buttonRef.current[propertyName] * 2
    );
  }

  function handleBackward() {
    setOffset(offset => Math.min(0, offset + getStep()));
  }

  function handleForward() {
    setOffset(offset => Math.max(0 - getMaxOffset(), offset - getStep()));
  }

  return (
    <div className={`${classPrefix}-tabs__tabbar`} style={style}>
      <div
        ref={scrollAreaRef}
        className={classNames(`${classPrefix}-tabs__scroll-area`, {
          "is-scrolling": scrolling && !disableTabScrolling,
        })}
        style={{
          maxHeight: vertical ? maxHeight : undefined,
        }}
      >
        <ul
          ref={tabListRef}
          className={`${classPrefix}-tabs__tablist`}
          style={{
            transition: "transform ease-out .2s",
            transform: vertical
              ? `translate3d(0, ${offset}px, 0)`
              : `translate3d(${offset}px, 0, 0)`,
          }}
        >
          {tabs.map(tab => (
            <TabItem
              ref={tab.id === activeId ? activeItemRef : undefined}
              key={tab.id}
              label={tab.label}
              actived={tab.id === activeId}
              disabled={tab.disabled}
              onClose={tab.onClose ? evt => tab.onClose(tab, evt) : null}
              onClick={evt => onActive(tab, evt)}
              render={children => tabBarRender(children, tab)}
              className={tab.className}
              style={tab.style}
            />
          ))}
        </ul>
        <Button
          ref={buttonRef}
          className={`${classPrefix}-tabs__backward`}
          type="icon"
          htmlType="button"
          icon={vertical ? "arrowup" : "arrowleft"}
          disabled={offset >= 0}
          onClick={handleBackward}
        />
        <Button
          className={`${classPrefix}-tabs__forward`}
          type="icon"
          htmlType="button"
          icon={vertical ? "arrowdown" : "arrowright"}
          disabled={offset <= 0 - getMaxOffset()}
          onClick={handleForward}
        />
      </div>
      <div className={`${classPrefix}-tabs__addons`}>{addon}</div>
    </div>
  );
}

TabBar.displayName = "TabBar";
