import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

import React, { cloneElement, isValidElement, Component, Fragment, Children } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Measure from 'react-measure';
import { CLS_PREFIX } from '../../constants';
import Icon, { ICON_SIZE_16 } from '../Icon';
import Label from '../Label';
import Dropdown from '../Dropdown';
import Menu, { MenuItem } from '../Menu';
import Tab from './Tab';
import ResponsiveContext from '../ResponsiveContext';
import { wrapFunction } from '../utils';
import { jsxs as _jsxs } from "react/jsx-runtime";
import { jsx as _jsx } from "react/jsx-runtime";
const ADDON_LEFT_PADDING = 5;
const MIN_ADDON_WIDTH_DEFAULT = 150;
const COLLAPSED_SEARCH_WIDTH = 60;

/**
 * `Tabs` component is a content area with a group of individual [Tab](#!/Tab) elements, each displaying different content
 * in the same screen area. `Tabs` are used when you have too much content to display in one place at the same time, so
 * the content is broken into logical groups and each group is displayed under its own [Tab](#!/Tab) that serves both as a
 * group name and a navigation button.
 * @since 0.0.35
 */
class Tabs extends Component {
  constructor() {
    super(...arguments);
    _defineProperty(this, "state", {
      active: this.props.active || 1,
      collapsedLength: 0,
      compact: false,
      searching: false,
      monospacedWidth: null
    });
    _defineProperty(this, "widths", null);
    _defineProperty(this, "checkAdaptive", () => {
      let {
        compact,
        searching,
        collapsedLength
      } = this.state;
      const {
        addonMinWidth: addonMinWidthProp,
        search,
        monospaced
      } = this.props;
      const {
        widths,
        addon
      } = this;
      let monospacedWidth = null;
      const getMonospacedWidth = () => monospacedWidth;
      if (!widths) {
        return;
      }
      const addonMinWidth = ADDON_LEFT_PADDING + (addonMinWidthProp || (search ? search.props.minWidth : MIN_ADDON_WIDTH_DEFAULT));
      const searchWidth = compact && search ? COLLAPSED_SEARCH_WIDTH + ADDON_LEFT_PADDING : 0;
      const {
        more,
        container,
        margin
      } = widths;
      let tabs = widths.tabs.slice();
      const tabsNumber = tabs.length;
      let lastTabIndex = tabsNumber - 1 - collapsedLength;
      if (monospaced) {
        monospacedWidth = tabs.slice(0, lastTabIndex + 1).reduce((max, tab) => tab > max ? tab : max, 0);
        tabs = tabs.map(getMonospacedWidth);
      }
      const getListWidth = () => {
        let listWidth = monospaced ? margin * Math.max(0, tabsNumber - 1 - Math.max(0, collapsedLength - 1)) : 0;
        for (let i = 0; i <= lastTabIndex; ++i) {
          listWidth += tabs[i];
        }
        if (collapsedLength) {
          listWidth += more;
        }
        return listWidth;
      };
      let spaceForAddon = container - getListWidth();
      if (addon && !collapsedLength && !compact && spaceForAddon <= addonMinWidth) {
        compact = true;
      }
      let freeSpace = spaceForAddon - searchWidth;
      if (freeSpace <= 0) {
        // collapse
        for (let i = lastTabIndex; i >= 0; --i) {
          let width = tabs[i];
          if (monospaced && widths.tabs[i] === monospacedWidth) {
            monospacedWidth = widths.tabs.slice(0, lastTabIndex).reduce((max, tab) => tab > max ? tab : max, 0);
            tabs = tabs.map(getMonospacedWidth);
            width += (widths.tabs[i] - monospacedWidth) * lastTabIndex;
          }
          if (collapsedLength === 0) {
            width -= more;
          }
          freeSpace += width;
          ++collapsedLength;
          --lastTabIndex;
          if (freeSpace > 0) {
            break;
          }
        }
      } else {
        // expand
        for (let i = lastTabIndex + 1; i < tabsNumber; ++i) {
          let width = tabs[i];
          if (monospaced && widths.tabs[i] > monospacedWidth) {
            monospacedWidth = widths.tabs[i];
            tabs = tabs.map(getMonospacedWidth);
            width = monospacedWidth + (monospacedWidth - width) * (lastTabIndex + 1);
          }
          if (collapsedLength === 1) {
            width -= more;
          }
          if (freeSpace <= width) {
            break;
          }
          freeSpace -= width;
          --collapsedLength;
          ++lastTabIndex;
        }
      }
      if (collapsedLength || compact) {
        spaceForAddon = container - getListWidth();
        if (collapsedLength) {
          compact = true;
        } else if (spaceForAddon >= addonMinWidth) {
          compact = false;
          searching = false;
        }
      }
      const newState = {
        compact,
        searching,
        collapsedLength,
        monospacedWidth
      };
      const keys = Object.keys(newState);
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        if (JSON.stringify(newState[key]) === JSON.stringify(this.state[key])) {
          delete newState[key];
        }
      }
      if (Object.keys(newState).length) {
        this.setState(newState, () => {
          if (typeof newState.collapsedLength !== 'undefined' && this.state.collapsedLength !== newState.collapsedLength) {
            this.checkAdaptive();
          }
        });
      }
    });
    _defineProperty(this, "handleStartSearching", () => {
      this.setState({
        searching: true
      });
    });
    _defineProperty(this, "handleCancelSearching", () => {
      this.setState({
        searching: false
      }, this.checkAdaptive);
    });
    _defineProperty(this, "handleResize", () => {
      const {
        baseClassName
      } = this.props;
      if (this.tabsnavRef) {
        const tabElements = this.tabsnavRef.querySelectorAll(`.${baseClassName}__tab-list--fake .${baseClassName}__tab`);
        const more = tabElements[tabElements.length - 1];
        const tabs = Array.prototype.slice.call(tabElements, 0, -1).map(el => el.offsetWidth);
        this.widths = {
          tabs,
          more: more.offsetWidth,
          container: this.tabsnavRef.offsetWidth,
          margin: more.offsetWidth - more.querySelector(`.${baseClassName}__link`).offsetWidth
        };
      }
      this.checkAdaptive();
    });
    _defineProperty(this, "handleAddonResize", contentRect => {
      this.addon = contentRect.bounds;
      this.checkAdaptive();
    });
    _defineProperty(this, "renderTabItem", (tab, index, tabMode) => {
      const {
        baseClassName
      } = this.props;
      const {
        monospacedWidth,
        active
      } = this.state;
      if (!tab || tab.type !== Tab) {
        return null;
      }
      const {
        title,
        label,
        icon,
        onActivate,
        onClose,
        component: Tag = 'a',
        ...tabProps
      } = tab.props;
      const selected = index + 1 === active;
      const key = index.toString();
      const tabIcon = Icon.create(icon, {
        size: ICON_SIZE_16,
        className: `${baseClassName}__tab-icon`
      });
      const tabLabel = this.renderTabLabel(tabMode, label);
      const tabClose = this.renderTabClose(tabMode, onClose);
      const handleClick = () => this.onClick(index + 1);
      tabProps.tabIndex = tabProps.tabIndex || 0;
      tabProps.onKeyDown = wrapFunction(tabProps.onKeyDown, e => {
        if (e.key === 'Enter') {
          e.currentTarget.click();
        }
      });
      if (tabMode === 'menu-item') {
        return /*#__PURE__*/_jsx(MenuItem, {
          icon: tabIcon,
          label: /*#__PURE__*/_jsxs(Fragment, {
            children: [tabLabel, tabClose]
          }),
          active: selected,
          onClick: handleClick,
          className: `${baseClassName}__menu-item`,
          component: Tag,
          ...tabProps,
          children: title
        }, key);
      }
      return /*#__PURE__*/_jsx("li", {
        className: classNames(`${baseClassName}__tab`, selected && `${baseClassName}__tab--selected`, tabClose && `${baseClassName}__tab--closable`),
        role: "presentation",
        children: /*#__PURE__*/_jsxs(Tag, {
          className: `${baseClassName}__link`,
          role: "tab",
          "aria-selected": selected || null,
          style: {
            width: monospacedWidth
          },
          onClick: handleClick,
          ...tabProps,
          children: [tabIcon, /*#__PURE__*/_jsx("span", {
            className: `${baseClassName}__tab-title`,
            children: title
          }), tabLabel, tabClose]
        })
      }, key);
    });
  }
  static getDerivedStateFromProps(props, state) {
    const {
      active
    } = props;
    const {
      prevActive
    } = state;
    const nextState = {};
    if (active && active !== prevActive) {
      nextState.active = active;
    }
    nextState.prevActive = active;
    return nextState;
  }
  componentDidUpdate() {
    if (!this.widths || this.props.children.length !== this.widths.tabs.length) {
      setTimeout(() => this.handleResize(), 0);
    }
  }
  onClick(active) {
    this.setState({
      active
    });
    const tab = this.props.children[active - 1];
    const {
      onActivate
    } = tab.props;
    if (onActivate) {
      onActivate();
    }
  }
  renderTabLabel(tabMode, label) {
    const {
      baseClassName
    } = this.props;
    if (typeof label === 'string') {
      return /*#__PURE__*/_jsx(Label, {
        className: `${baseClassName}__${tabMode}-label`,
        intent: "danger",
        children: label
      });
    }
    if ( /*#__PURE__*/isValidElement(label)) {
      return /*#__PURE__*/cloneElement(label, {
        className: classNames(`${baseClassName}__${tabMode}-label`, label.props.className)
      });
    }
    return null;
  }
  renderTabClose(tabMode, onClose) {
    const {
      baseClassName
    } = this.props;
    if (typeof onClose === 'function') {
      return /*#__PURE__*/_jsx("button", {
        className: `${baseClassName}__${tabMode}-close`,
        type: "button",
        onClick: e => {
          e.preventDefault();
          e.stopPropagation();
          onClose(e);
        },
        children: /*#__PURE__*/_jsx(Icon, {
          className: `${baseClassName}__${tabMode}-close-icon`,
          name: "cross-mark"
        })
      });
    }
    return null;
  }
  renderFakeTabs() {
    const {
      baseClassName,
      children
    } = this.props;
    const childrenCount = Children.count(children);
    if (!childrenCount) {
      return null;
    }
    return /*#__PURE__*/_jsxs("ul", {
      className: classNames(`${baseClassName}__tab-list`, `${baseClassName}__tab-list--fake`),
      children: [Children.map(children, tab => {
        if (!tab || tab.type !== Tab) {
          return null;
        }
        const {
          title,
          label,
          icon,
          onActivate,
          onClose,
          ...tabProps
        } = tab.props;
        const iconBlock = Icon.create(icon, {
          size: ICON_SIZE_16,
          className: `${baseClassName}__tab-icon`
        });
        const closeBlock = this.renderTabClose('tab', onClose);
        return /*#__PURE__*/_jsxs("li", {
          className: classNames(`${baseClassName}__tab`, closeBlock && `${baseClassName}__tab--closable`),
          children: [/*#__PURE__*/_jsxs("a", {
            className: `${baseClassName}__link`,
            tabIndex: "-1",
            style: tabProps.style,
            children: [iconBlock, /*#__PURE__*/_jsx("span", {
              className: `${baseClassName}__tab-title`,
              children: title
            }), this.renderTabLabel('tab', label)]
          }), closeBlock]
        }, title);
      }), /*#__PURE__*/_jsx("li", {
        className: classNames(`${baseClassName}__tab`, `${baseClassName}__tab--more`),
        children: /*#__PURE__*/_jsx("a", {
          className: `${baseClassName}__link`,
          tabIndex: "-1",
          children: /*#__PURE__*/_jsx(Icon, {
            name: "three-dots-horizontal"
          })
        })
      })]
    });
  }
  createTabItems() {
    const {
      children
    } = this.props;
    const {
      collapsedLength
    } = this.state;
    const visibleItems = [];
    const hiddenItems = [];
    const lastTabIndex = Children.count(children) - 1 - collapsedLength;
    Children.forEach(children, (child, index) => {
      const hidden = index > lastTabIndex;
      const tabMode = hidden ? 'menu-item' : 'tab';
      (hidden ? hiddenItems : visibleItems).push(this.renderTabItem(child, index, tabMode));
    });
    return {
      visibleItems,
      hiddenItems
    };
  }
  renderTabList() {
    const {
      baseClassName,
      children
    } = this.props;
    const {
      active
    } = this.state;
    if (!Children.toArray(children).length) {
      return null;
    }
    const {
      visibleItems,
      hiddenItems
    } = this.createTabItems();
    const moreSelected = active > visibleItems.length;
    return /*#__PURE__*/_jsxs("ul", {
      className: `${baseClassName}__tab-list`,
      role: "tablist",
      children: [visibleItems, hiddenItems.length > 0 && /*#__PURE__*/_jsx("li", {
        ref: ref => this.moreTabsRef = ref,
        className: classNames(`${baseClassName}__tab`, moreSelected && `${baseClassName}__tab--selected`, `${baseClassName}__tab--more`),
        role: "presentation",
        "aria-selected": moreSelected || null,
        children: /*#__PURE__*/_jsx(Dropdown, {
          className: `${baseClassName}__dropdown`,
          menu: /*#__PURE__*/_jsx(Menu, {
            children: hiddenItems
          }),
          menuPlacement: "bottom-end",
          children: /*#__PURE__*/_jsx("a", {
            className: `${baseClassName}__link`,
            role: "tab",
            tabIndex: "0",
            "aria-selected": moreSelected || null,
            children: /*#__PURE__*/_jsx(Icon, {
              name: "three-dots-horizontal"
            })
          })
        })
      })]
    });
  }
  renderSearchBar(searchProps) {
    const {
      baseClassName,
      search
    } = this.props;
    const {
      compact
    } = this.state;
    const clone = /*#__PURE__*/cloneElement(search, searchProps);
    if (compact) {
      return /*#__PURE__*/_jsx("div", {
        className: `${baseClassName}__search`,
        children: clone
      });
    }
    return clone;
  }
  render() {
    const {
      baseClassName,
      className,
      addon,
      placeholder,
      children,
      active,
      addonMinWidth,
      monospaced,
      search,
      ...props
    } = this.props;
    const {
      compact,
      searching
    } = this.state;
    const childrenCount = Children.count(children);
    if (!childrenCount) {
      return null;
    }
    let addonBlock = addon || placeholder;
    const addonProps = {};
    let searchBlock = null;
    if (search) {
      const searchProps = {
        collapsable: compact,
        onExpand: this.handleStartSearching,
        onCollapse: this.handleCancelSearching
      };
      if (compact) {
        if (searching) {
          searchProps.maxWidth = null;
          searchProps.minWidth = null;
          searchProps.autoFocus = true;
          searchProps.responsive = false;
        } else {
          searchProps.onSearch = this.handleStartSearching;
        }
        searchBlock = this.renderSearchBar(searchProps);
      } else if (addonBlock) {
        searchProps.key = 1;
        addonBlock = [this.renderSearchBar(searchProps), /*#__PURE__*/cloneElement(addonBlock, {
          key: 2
        })];
      } else {
        addonProps.style = {
          maxWidth: search.props.maxWidth
        };
        addonBlock = this.renderSearchBar(searchProps);
      }
    }
    return /*#__PURE__*/_jsx(ResponsiveContext.Provider, {
      value: compact,
      children: /*#__PURE__*/_jsxs("div", {
        className: classNames(baseClassName, className),
        ...props,
        children: [/*#__PURE__*/_jsx(Measure, {
          onResize: this.handleResize,
          innerRef: ref => this.tabsnavRef = ref,
          children: _ref => {
            let {
              measureRef
            } = _ref;
            return /*#__PURE__*/_jsxs("div", {
              className: classNames(`${baseClassName}__nav`, compact && `${baseClassName}__nav--compact`, searching && `${baseClassName}__nav--searching`, search && `${baseClassName}__nav--search`),
              ref: measureRef,
              children: [this.renderTabList(), /*#__PURE__*/_jsx(Measure, {
                onResize: this.handleResize,
                children: _ref2 => {
                  let {
                    measureRef: ref
                  } = _ref2;
                  return /*#__PURE__*/cloneElement(this.renderFakeTabs(), {
                    ref
                  });
                }
              }), searchBlock, addonBlock && /*#__PURE__*/_jsx(Measure, {
                onResize: this.handleAddonResize,
                bounds: true,
                children: _ref3 => {
                  let {
                    measureRef: ref
                  } = _ref3;
                  return /*#__PURE__*/_jsx("div", {
                    className: `${baseClassName}__addon`,
                    ref: ref,
                    ...addonProps,
                    children: addonBlock
                  });
                }
              })]
            });
          }
        }), /*#__PURE__*/_jsx("div", {
          className: `${baseClassName}__tab-panel`,
          role: "tabpanel",
          children: Children.map(children, (tab, index) => index + 1 === this.state.active ? tab : null)
        })]
      })
    });
  }
}
Tabs.propTypes = {
  /**
   * Number of active tab
   * @since 0.0.35
   */
  active: PropTypes.number,
  /**
   * Addon for search bar, dropdown etc.
   * @since 0.0.58
   */
  addon: PropTypes.element,
  /**
   * Placeholder for search bar, dropdown etc.
   *
   * @deprecated Do not use! Use `addon` instead!
   * @since 0.0.42
   */
  placeholder: PropTypes.element,
  /**
   * Minimum add-on width in pixels
   * @since 0.0.58
   */
  addonMinWidth: PropTypes.number,
  /**
   * Monospaced version of tabs (all visible tabs as wide as widest of them)
   * @since 0.0.58
   */
  monospaced: PropTypes.bool,
  /**
   * [SearchBar](#!/SearchBar) element
   * @since 0.0.58
   */
  search: PropTypes.element,
  /**
   * [Tabs](#!/Tab)
   * @since 0.0.47
   */
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.element), PropTypes.element]),
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * @ignore
   */
  baseClassName: PropTypes.string
};
Tabs.defaultProps = {
  active: null,
  addon: null,
  placeholder: null,
  addonMinWidth: null,
  monospaced: null,
  search: null,
  children: null,
  className: null,
  baseClassName: `${CLS_PREFIX}tabs`
};
export default Tabs;