import React, { useEffect, useMemo, useRef, useState } from "react";
import {
  CascaderData,
  CascaderBoxProps,
  CascaderMultipleProps,
} from "../CascaderProps";
import { EmptyTip } from "../../tips";
import { CheckTree } from "../../checktree";
import { getOptions } from "../CascaderBox";
import { List } from "../../list";
import { Checkbox } from "../../checkbox";
import { CascaderLoading } from "../CascaderLoading";
import { useTranslation } from "../../i18n";
import { useConfig } from "../../util";
import { noop } from "../../_util/noop";

// CheckTree 需要数值形式多段值转为字符串值，使用该字符串拼接
export const separator = "_#$SEP$_";
export const defaultAllValue = "__CascaderAllValue__";

export function getRelations(
  data: CascaderData,
  all: CascaderMultipleProps["all"]
) {
  const relations = {};
  const disabledNames = [];
  const traverse = (data: CascaderData, parentValue: string) => {
    (data.options || []).forEach(option => {
      const value =
        parentValue === null
          ? option.value
          : `${parentValue}${separator}${option.value}`;
      if (parentValue !== null) {
        relations[value] = parentValue;
      } else if (all) {
        relations[value] = (all as any)?.value || defaultAllValue;
      }
      if (option.disabled) {
        disabledNames.push(value);
      }
      if (option.child) {
        traverse(option.child as CascaderData, value);
      }
    });
  };

  traverse(data, null);
  return { relations, disabledNames };
}

export function CascaderMultiMenuLists({
  data,
  curValueList,
  onChange,
  onLoad,
  onSelect,
  expandTrigger,
  scheduleUpdate,
  all,
  tips,
  bottomTips,
  onScrollBottom = noop,
}: CascaderBoxProps) {
  const enterTimerRef = useRef(null);
  const t = useTranslation();
  const { classPrefix } = useConfig();
  const allValue = (all as any)?.value || defaultAllValue;

  // 内部状态
  const [internalValue, setInternalValue] = useState([]);

  const { relations, disabledNames } = useMemo(() => getRelations(data, all), [
    data,
    all,
  ]);

  const lists = useMemo(() => {
    const lists = [data];
    internalValue.forEach(value => {
      const option = lists[lists.length - 1].options.find(
        option => option.value === value
      );
      if (option && option.child) {
        lists.push(option.child as CascaderData);
      }
    });
    return lists;
  }, [data, internalValue]);

  useEffect(() => {
    if (scheduleUpdate) {
      scheduleUpdate();
    }
  }, [lists, scheduleUpdate]);

  function handleSelect(index, value, { event, hasChild }) {
    const newValue = [...internalValue.slice(0, index), value];
    setInternalValue(newValue);
    if (!hasChild) {
      onSelect(newValue, { event, options: getOptions(data, newValue) });
    }
  }

  return (
    <CheckTree
      relations={relations}
      disabledNames={disabledNames}
      value={curValueList.map(list => list.join(separator))}
      onChange={(names, { event }) => {
        const value = names.map(name => name.split(separator));
        onChange(value, {
          event,
          options: value.map(i => getOptions(data, i)),
        });
      }}
    >
      {lists.map(({ options }, index) => (
        <List
          type="option"
          className={`${classPrefix}-list--checkoption`}
          key={index}
          onScrollBottom={() => onScrollBottom(internalValue.slice(0, index))}
        >
          {options ? (
            <>
              {tips && (
                <List.StatusTip>
                  {tips(internalValue.slice(0, index))}
                </List.StatusTip>
              )}
              {index === 0 && all && (
                <List.Item>
                  <Checkbox name={allValue}>
                    {(all as any)?.label || t.selectAllText}
                  </Checkbox>
                </List.Item>
              )}
              {options.map(({ value, label, child, disabled }) => {
                const optionValue = [...internalValue.slice(0, index), value];
                let triggerProps = {};

                if (child) {
                  triggerProps =
                    expandTrigger === "hover" && child
                      ? {
                          onMouseEnter: (event: React.MouseEvent) => {
                            enterTimerRef.current = setTimeout(() => {
                              handleSelect(index, value, {
                                event,
                                hasChild: true,
                              });
                            }, 150);
                          },
                          onMouseLeave: () => {
                            clearTimeout(enterTimerRef.current);
                          },
                        }
                      : {
                          onClick: (event: React.MouseEvent) => {
                            handleSelect(index, value, {
                              event,
                              hasChild: Boolean(child),
                            });
                          },
                        };
                }

                const itemProps = {
                  ...triggerProps,
                  key: [...internalValue.slice(0, index), value].join("/"),
                  disabled,
                  selected: false,
                };

                if (child) {
                  return (
                    <List.SubMenu
                      {...itemProps}
                      label={
                        <>
                          <Checkbox
                            name={optionValue.join(separator)}
                            style={{ paddingRight: 0, display: "inline-block" }}
                          />
                          <div
                            style={{
                              display: "inline-block",
                              marginRight: 28,
                              lineHeight: "30px",
                            }}
                          >
                            {label || value}
                          </div>
                        </>
                      }
                    />
                  );
                }

                return (
                  <List.Item {...itemProps}>
                    <Checkbox
                      name={optionValue.join(separator)}
                      {...triggerProps}
                    >
                      {label || value}
                    </Checkbox>
                  </List.Item>
                );
              })}
              {options.length === 0 && (
                <List.StatusTip>
                  <EmptyTip />
                </List.StatusTip>
              )}
              {bottomTips && (
                <List.StatusTip>
                  {bottomTips(internalValue.slice(0, index))}
                </List.StatusTip>
              )}
            </>
          ) : (
            <List.StatusTip>
              <CascaderLoading
                onLoad={() =>
                  onLoad(internalValue, getOptions(data, internalValue))
                }
              />
            </List.StatusTip>
          )}
        </List>
      ))}
    </CheckTree>
  );
}

CascaderMultiMenuLists.displayName = "CascaderMultiMenuLists";
