import React, { isValidElement, useContext, useEffect, useState } from "react";
import classnames from "classnames";
import { extend } from "../utils";
import { useSetState, useUpdateEffect } from "../hooks";
import Icon from "../icon";
import Tabs from "../tabs";
import ConfigProviderContext from "../config-provider/ConfigProviderContext";
import useMountedRef from "../hooks/use-mounted-ref";
const INITIAL_STATE = {
  tabs: [],
  activeTab: 0
};
const Cascader = (props) => {
  const {
    prefixCls,
    createNamespace
  } = useContext(ConfigProviderContext);
  const [bem] = createNamespace("cascader", prefixCls);
  const [internalValue, setInternalValue] = useState(void 0);
  const [state, updateState] = useSetState(INITIAL_STATE);
  const mountedRef = useMountedRef();
  const {
    text: textKey,
    value: valueKey,
    children: childrenKey
  } = extend({
    text: "text",
    value: "value",
    children: "children"
  }, props.fieldNames);
  const getSelectedOptionsByValue = (options, value) => {
    for (let i = 0; i < options.length; i++) {
      const option = options[i];
      if (option[valueKey] === value) {
        return [option];
      }
      if (option[childrenKey]) {
        const selectedOptions = getSelectedOptionsByValue(option[childrenKey], value);
        if (selectedOptions) {
          return [option, ...selectedOptions];
        }
      }
    }
    return void 0;
  };
  const updateTabs = () => {
    if (internalValue || internalValue === 0) {
      const selectedOptions = getSelectedOptionsByValue(props.options, internalValue);
      if (selectedOptions) {
        let optionsCursor = props.options;
        const tabs = selectedOptions.map((option) => {
          const tab = {
            options: optionsCursor,
            selectedOption: option
          };
          const next = optionsCursor.find((item) => item[valueKey] === option[valueKey]);
          if (next) {
            optionsCursor = next[childrenKey];
          }
          return tab;
        });
        if (optionsCursor) {
          tabs.push({
            options: optionsCursor,
            selectedOption: null
          });
        }
        updateState({
          tabs
        });
        setTimeout(() => {
          if (mountedRef.current) {
            updateState({
              activeTab: tabs.length - 1
            });
          }
        }, 0);
        return;
      }
    }
    updateState({
      tabs: [{
        options: props.options,
        selectedOption: null
      }]
    });
  };
  const onSelect = (option, tabIndex) => {
    var _a, _b;
    if (option.disabled) {
      return;
    }
    let tabs = JSON.parse(JSON.stringify(state.tabs));
    tabs[tabIndex].selectedOption = option;
    if (tabs.length > tabIndex + 1) {
      tabs = tabs.slice(0, tabIndex + 1);
    }
    if (option[childrenKey]) {
      const nextTab = {
        options: option[childrenKey],
        selectedOption: null
      };
      if (tabs[tabIndex + 1]) {
        tabs[tabIndex + 1] = nextTab;
      } else {
        tabs.push(nextTab);
      }
      updateState({
        tabs,
        activeTab: state.activeTab + 1
      });
    }
    const selectedOptions = tabs.map((tab) => tab.selectedOption).filter(Boolean);
    const eventParams = {
      value: option[valueKey],
      tabIndex,
      selectedOptions
    };
    setInternalValue(option[valueKey]);
    (_a = props.onChange) == null ? void 0 : _a.call(props, eventParams);
    if (!option[childrenKey]) {
      (_b = props.onFinish) == null ? void 0 : _b.call(props, eventParams);
    }
  };
  const onClose = () => {
    var _a;
    return (_a = props.onClose) == null ? void 0 : _a.call(props);
  };
  const onClickTab = ({
    name,
    title
  }) => {
    var _a;
    updateState({
      activeTab: +name
    });
    (_a = props.onClickTab) == null ? void 0 : _a.call(props, +name, title);
  };
  const getStateFromValue = (value) => {
    if (!value || !value.length)
      return INITIAL_STATE;
    try {
      const initialState = {
        activeTab: value.length - 1,
        tabs: []
      };
      value.reduce((options, v) => {
        const selectedOption = options.find((tabs) => tabs[valueKey] === v);
        if (!selectedOption) {
          throw Error("Cascader: unable to match options correctly, Please check value or defaultValue props.");
        }
        initialState.tabs.push({
          options,
          selectedOption
        });
        return selectedOption[childrenKey];
      }, props.options);
      return initialState;
    } catch (error) {
      console.error(error);
      return INITIAL_STATE;
    }
  };
  const renderCloseIcon = () => {
    if (!props.closeable)
      return null;
    if (typeof props.closeIcon === "string") {
      return /* @__PURE__ */ React.createElement(Icon, {
        name: props.closeIcon,
        className: classnames(bem("close-icon")),
        onClick: onClose
      });
    }
    if (/* @__PURE__ */ isValidElement(props.closeIcon)) {
      return props.closeIcon;
    }
    return null;
  };
  const renderHeader = () => /* @__PURE__ */ React.createElement("div", {
    className: classnames(bem("header"))
  }, /* @__PURE__ */ React.createElement("h2", {
    className: classnames(bem("title"))
  }, props.title), renderCloseIcon());
  const renderOption = (option, selectedOption, tabIndex) => {
    const selected = selectedOption && option[valueKey] === selectedOption[valueKey];
    const color = option.color || (selected ? props.activeColor : void 0);
    const Text = props.optionRender ? props.optionRender({
      option,
      selected
    }) : /* @__PURE__ */ React.createElement("span", null, option[textKey]);
    return /* @__PURE__ */ React.createElement("li", {
      key: option[valueKey],
      className: classnames(bem("option", {
        selected,
        disabled: option.disabled
      }), option.className),
      style: {
        color
      },
      onClick: () => onSelect(option, tabIndex)
    }, Text, selected ? /* @__PURE__ */ React.createElement(Icon, {
      name: "success",
      className: classnames(bem("selected-icon"))
    }) : null);
  };
  const renderOptions = (options, selectedOption, tabIndex) => /* @__PURE__ */ React.createElement("ul", {
    key: tabIndex,
    className: classnames(bem("options"))
  }, options.map((option) => renderOption(option, selectedOption, tabIndex)));
  const renderTab = (tab, tabIndex) => {
    const {
      options,
      selectedOption
    } = tab;
    const title = selectedOption ? selectedOption[textKey] : props.placeholder || "\u8BF7\u9009\u62E9";
    return /* @__PURE__ */ React.createElement(Tabs.TabPane, {
      key: tabIndex,
      title,
      titleClass: classnames(bem("tab", {
        unselected: !selectedOption
      }))
    }, renderOptions(options, selectedOption, tabIndex));
  };
  const renderTabs = () => /* @__PURE__ */ React.createElement(Tabs, {
    animated: true,
    active: state.activeTab,
    className: classnames(bem("tabs")),
    color: props.activeColor,
    swipeThreshold: 0,
    swipeable: props.swipeable,
    onClickTab
  }, state.tabs.map(renderTab));
  useEffect(() => {
    updateTabs();
  }, [JSON.stringify(props.options)]);
  useEffect(() => {
    var _a;
    const value = (_a = props.value) != null ? _a : props.defaultValue;
    if (!value || Array.isArray(value) && !value.length)
      return;
    const initialState = getStateFromValue(value);
    updateState(initialState);
  }, []);
  useUpdateEffect(() => {
    const initialState = getStateFromValue(props.value);
    updateState(initialState);
  }, [props.value]);
  useUpdateEffect(() => {
    if (internalValue || internalValue === 0) {
      const values = state.tabs.map((tab) => {
        var _a;
        return (_a = tab.selectedOption) == null ? void 0 : _a[valueKey];
      });
      if (values.includes(internalValue)) {
        return;
      }
    }
    updateTabs();
  }, [internalValue]);
  return /* @__PURE__ */ React.createElement("div", {
    className: classnames(bem())
  }, renderHeader(), state.tabs.length ? renderTabs() : null);
};
Cascader.defaultProps = {
  closeable: true,
  swipeable: true,
  options: [],
  closeIcon: "cross"
};
var stdin_default = Cascader;
export {
  stdin_default as default
};
