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

import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { CLS_PREFIX } from '../../constants';
import ButtonGroup from '../ButtonGroup';
import Button from '../Button';
import Dropdown from '../Dropdown';
import Menu, { MenuItem } from '../Menu';
import Squeezer from '../Squeezer';
import ResponsiveContext from '../ResponsiveContext';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
const alphaSort = (a, b) => a > b ? 1 : -1;

/**
 *  `Segmented Control` is a group of several [Buttons](#!/Button)
 * each of which functions as a mutually exclusive option.
 * @since 0.0.68
 */
class SegmentedControl extends Component {
  constructor() {
    super(...arguments);
    _defineProperty(this, "state", {
      selected: this.props.selected,
      monoWidth: 0
    });
    _defineProperty(this, "isCompact", false);
    _defineProperty(this, "rootRef", /*#__PURE__*/createRef());
    _defineProperty(this, "adjustMonospaced", () => {
      const {
        baseClassName,
        monospaced
      } = this.props;
      if (monospaced) {
        let monoWidth = 0;
        this.rootRef.current.querySelectorAll(`.${baseClassName}__button`).forEach(el => {
          monoWidth = Math.max(monoWidth, el.getBoundingClientRect().width);
        });
        if (monoWidth !== this.state.monoWidth) {
          this.setState({
            monoWidth
          });
        }
      }
    });
    _defineProperty(this, "handleChange", value => () => {
      const {
        multiple,
        onChange
      } = this.props;
      const {
        selected
      } = this.state;
      let newSelected;
      if (multiple) {
        newSelected = selected ? selected.slice() : [];
        if (!selected || !(selected instanceof Array) || selected.indexOf(value) === -1) {
          newSelected.push(value);
        } else {
          newSelected.splice(selected.indexOf(value), 1);
        }
        newSelected.sort(alphaSort);
      } else {
        newSelected = value;
      }
      if (selected instanceof Array) {
        selected.sort(alphaSort);
      }
      if (JSON.stringify(newSelected) !== JSON.stringify(selected)) {
        this.setState({
          selected: newSelected
        });
        onChange(newSelected);
      }
    });
    _defineProperty(this, "compact", () => {
      if (this.isCompact) {
        return false;
      }
      this.isCompact = true;
      this.forceUpdate();
      return true;
    });
    _defineProperty(this, "uncompact", () => {
      if (!this.isCompact) {
        return false;
      }
      this.isCompact = false;
      this.forceUpdate();
      return true;
    });
  }
  static getDerivedStateFromProps(props, state) {
    const {
      selected,
      multiple
    } = props;
    const {
      prevSelected
    } = state;
    const nextState = {
      selected: state.selected
    };
    if (selected !== prevSelected) {
      nextState.selected = selected;
    }
    if (multiple && nextState.selected && !(nextState.selected instanceof Array)) {
      nextState.selected = [nextState.selected];
    }
    nextState.prevSelected = selected;
    return nextState;
  }
  componentDidMount() {
    this.adjustMonospaced();
  }
  componentDidUpdate() {
    this.adjustMonospaced();
  }
  isResponsive() {
    return this.context === undefined ? this.isCompact : this.context;
  }
  renderControl() {
    const {
      buttons,
      multiple
    } = this.props;
    const hasIcons = buttons.some(_ref => {
      let {
        icon
      } = _ref;
      return !!icon;
    });
    if (!hasIcons && !multiple && this.isResponsive()) {
      return this.renderDropdown();
    }
    return this.renderButtonGroup();
  }
  renderDropdown() {
    const {
      buttons,
      onChange
    } = this.props;
    const {
      selected
    } = this.state;
    const {
      title
    } = buttons.find(button => button.value === selected) || {};
    const menu = /*#__PURE__*/_jsx(Menu, {
      children: buttons.map(_ref2 => {
        let {
          title,
          value,
          ...buttonProps
        } = _ref2;
        const menuItemProps = {};
        if (onChange !== null) {
          menuItemProps.onClick = this.handleChange(value);
        }
        return /*#__PURE__*/_jsx(MenuItem, {
          ...buttonProps,
          ...menuItemProps,
          children: title
        }, value);
      })
    });
    return /*#__PURE__*/_jsx(Dropdown, {
      menu: menu,
      children: title
    });
  }
  renderButtonGroup() {
    const {
      buttons,
      monospaced,
      multiple,
      onChange,
      ghost,
      baseClassName
    } = this.props;
    const {
      selected,
      monoWidth
    } = this.state;
    const isCollapsed = this.state.compact;
    return /*#__PURE__*/_jsx(ButtonGroup, {
      className: `${baseClassName}__button-group`,
      children: buttons.map(_ref3 => {
        let {
          value,
          title,
          ...buttonProps
        } = _ref3;
        // uncontrolled
        const handler = {};
        if (onChange !== null) {
          handler.onClick = this.handleChange(value);
        }
        let buttonSelected = false;
        if (multiple && selected && selected instanceof Array && selected.indexOf(value) !== -1) {
          buttonSelected = true;
        } else if (!multiple && selected === value) {
          buttonSelected = true;
        }
        buttonProps.className = classNames(buttonProps.className, `${baseClassName}__button`);
        if (!isCollapsed && monospaced && monoWidth) {
          buttonProps.style = {
            width: monoWidth,
            ...buttonProps.style
          };
        }
        return /*#__PURE__*/_jsx(Button, {
          selected: buttonSelected,
          ghost: ghost,
          ...handler,
          ...buttonProps,
          children: title
        }, value);
      })
    });
  }
  render() {
    const {
      label,
      labelPlacement,
      buttons,
      monospaced,
      multiple,
      selected: selectedProp,
      onChange,
      inline,
      ghost,
      className,
      baseClassName,
      ...props
    } = this.props;
    const isCollapsed = this.isResponsive();
    return /*#__PURE__*/_jsx(ResponsiveContext.Provider, {
      value: isCollapsed,
      children: /*#__PURE__*/_jsx(Squeezer, {
        compact: this.compact,
        uncompact: this.uncompact,
        innerRef: el => {
          this.rootRef.current = el;
        },
        children: _ref4 => {
          let {
            ref
          } = _ref4;
          return /*#__PURE__*/_jsxs("div", {
            ref: ref,
            className: classNames(baseClassName, {
              [`${baseClassName}--inline`]: inline,
              [`${baseClassName}--collapsed`]: isCollapsed,
              [`${baseClassName}--vertical`]: label && labelPlacement === 'top'
            }, className),
            ...props,
            children: [label && /*#__PURE__*/_jsx("div", {
              className: `${baseClassName}__label`,
              children: label
            }), this.renderControl()]
          });
        }
      })
    });
  }
}
SegmentedControl.propTypes = {
  /**
   * Label
   * @since 0.0.68
   */
  label: PropTypes.node,
  /**
   * Where to place label
   * @since 0.0.68
   */
  labelPlacement: PropTypes.oneOf(['top', 'left']),
  /**
   * Array of buttons to display (every array item must contain an unique "value" property)
   * @since 0.0.68
   */
  buttons: PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.any.isRequired,
    title: PropTypes.node
  })).isRequired,
  /**
   * Monospaced version of buttons (all button would have the same width).
   * Attention: using it with buttons dynamic update may cause to wrong behavior!
   * @since 0.0.68
   */
  monospaced: PropTypes.bool,
  /**
   * Multiple selected options version (any number of buttons can be selected)
   * @since 0.0.68
   */
  multiple: PropTypes.bool,
  /**
   * Selected value or an array of values (for multiple version).
   * Used in controlled version or as default value in uncontrolled version (with onChange property)
   * @since 0.0.68
   */
  selected: PropTypes.oneOfType([PropTypes.any, PropTypes.arrayOf(PropTypes.any)]).isRequired,
  /**
   * On change selection callback for uncontrolled mode.
   * @since 0.0.68
   */
  onChange: PropTypes.func,
  /**
   * Should component displays as inline element?
   * @since 0.0.68
   */
  inline: PropTypes.bool,
  /**
   * Use buttons with transparent background (ghost buttons)
   * @since 2.3.0
   */
  ghost: PropTypes.bool,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * @ignore
   */
  baseClassName: PropTypes.string
};
SegmentedControl.defaultProps = {
  label: null,
  labelPlacement: 'top',
  monospaced: false,
  multiple: false,
  onChange: null,
  inline: false,
  ghost: false,
  className: null,
  baseClassName: `${CLS_PREFIX}segmented-control`
};
SegmentedControl.contextType = ResponsiveContext;
export default SegmentedControl;