import _extends from "@babel/runtime/helpers/esm/extends";
import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose";
var _class, _Sticky;
import React from 'react';
import shallowEqual from 'shallowequal';
import { globalObject } from '@skbkontur/global-object';
import * as LayoutEvents from "../../../lib/LayoutEvents";
import { isFunction } from "../../../lib/utils";
import { ZIndex } from "../../../internal/ZIndex";
import { CommonWrapper } from "../../../internal/CommonWrapper";
import { cx } from "../../../lib/theming/Emotion";
import { rootNode } from "../../../lib/rootNode";
import { getDOMRect } from "../../../lib/dom/getDOMRect";
import { createPropsGetter } from "../../../lib/createPropsGetter";
import { getFullReactUIFlagsContext, ReactUIFeatureFlagsContext } from "../../../lib/featureFlagsContext";
import { styles } from "../Sticky.styles";
var MAX_REFLOW_RETRIES = 5;
export var StickyDataTids = {
  root: 'Sticky__root'
};

/**
 * `Sticky` позволяет закреплять элемент интерфейса в определенной позиции на экране при прокрутке страницы.
 * Это полезно для создания "прилипающих" элементов, которые остаются видимыми при прокрутке содержимого.
 */
export var Sticky = rootNode(_class = (_Sticky = /*#__PURE__*/function (_React$Component) {
  function Sticky() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
    _this.getProps = createPropsGetter(Sticky.defaultProps);
    _this.state = {
      fixed: false,
      deltaHeight: 0,
      stopped: false,
      relativeTop: 0
    };
    _this.layoutSubscription = {
      remove: null
    };
    _this.reflowCounter = 0;
    _this.refWrapper = function (ref) {
      return _this.wrapper = ref;
    };
    _this.refInner = function (ref) {
      return _this.inner = ref;
    };

    /**
     * Пересчитать габариты и позицию залипшего элемента
     *
     * @public
     */
    _this.reflow = function () {
      var _globalObject$documen;
      if (!((_globalObject$documen = globalObject.document) != null && _globalObject$documen.documentElement)) {
        throw Error('There is no "documentElement" in document');
      }
      var windowHeight = globalObject.innerHeight || globalObject.document.documentElement.clientHeight;
      if (!_this.wrapper || !_this.inner) {
        return;
      }
      var _getDOMRect = getDOMRect(_this.wrapper),
        top = _getDOMRect.top,
        bottom = _getDOMRect.bottom,
        left = _getDOMRect.left,
        width = _getDOMRect.width;
      var _getDOMRect2 = getDOMRect(_this.inner),
        height = _getDOMRect2.height;
      var _this$props = _this.props,
        getStop = _this$props.getStop,
        side = _this$props.side;
      var _this$state = _this.state,
        prevFixed = _this$state.fixed,
        _this$state$height = _this$state.height,
        prevHeight = _this$state$height === void 0 ? height : _this$state$height;
      var offset = _this.getProps().offset;
      var fixed = side === 'top' ? Math.ceil(top) < offset : Math.floor(bottom) > windowHeight - offset;
      _this.setState({
        fixed: fixed,
        left: left
      });
      if (fixed && !prevFixed) {
        _this.setState({
          width: width,
          height: height
        });
      }
      if (fixed) {
        _this.setState({
          width: width
        });
        var stop = getStop && getStop();
        if (stop) {
          var deltaHeight = prevHeight - height;
          var stopRect = getDOMRect(stop);
          var outerHeight = height + offset;
          var stopped = false;
          var relativeTop = 0;
          if (side === 'top') {
            stopped = stopRect.top - outerHeight < 0;
            relativeTop = stopRect.top - prevHeight - top;
          } else {
            stopped = stopRect.bottom + outerHeight > windowHeight;
            relativeTop = stopRect.bottom - top;
          }
          _this.setState({
            relativeTop: relativeTop,
            deltaHeight: deltaHeight,
            stopped: stopped
          });
        }
      }
    };
    return _this;
  }
  _inheritsLoose(Sticky, _React$Component);
  var _proto = Sticky.prototype;
  _proto.componentDidMount = function componentDidMount() {
    this.reflow();
    this.layoutSubscription = LayoutEvents.addListener(this.reflow);
  };
  _proto.componentWillUnmount = function componentWillUnmount() {
    if (this.layoutSubscription.remove) {
      this.layoutSubscription.remove();
    }
  };
  _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
    if (!shallowEqual(prevProps, this.props) || !shallowEqual(prevState, this.state)) {
      if (this.reflowCounter < MAX_REFLOW_RETRIES) {
        this.featureFlags.stickyReduceLayoutEvents ? this.reflow() : LayoutEvents.emit();
        this.reflowCounter += 1;
        return;
      }
    }
    this.reflowCounter = 0;
  };
  _proto.render = function render() {
    var _this2 = this;
    return /*#__PURE__*/React.createElement(ReactUIFeatureFlagsContext.Consumer, null, function (flags) {
      _this2.featureFlags = getFullReactUIFlagsContext(flags);
      return _this2.renderMain();
    });
  };
  _proto.renderMain = function renderMain() {
    var _cx;
    var children = this.props.children;
    var side = this.props.side;
    var offset = this.getProps().offset;
    var _this$state2 = this.state,
      fixed = _this$state2.fixed,
      stopped = _this$state2.stopped,
      relativeTop = _this$state2.relativeTop,
      deltaHeight = _this$state2.deltaHeight,
      width = _this$state2.width,
      height = _this$state2.height,
      left = _this$state2.left;
    var innerStyle = {};
    if (fixed) {
      if (stopped) {
        innerStyle.top = relativeTop;
        innerStyle[side === 'top' ? 'marginTop' : 'marginBottom'] = deltaHeight;
      } else {
        innerStyle.width = width;
        innerStyle[side] = offset;
        innerStyle.left = left;
      }
    }
    if (isFunction(children)) {
      children = children(fixed);
    }
    return /*#__PURE__*/React.createElement(CommonWrapper, _extends({
      rootNodeRef: this.setRootNode
    }, this.props), /*#__PURE__*/React.createElement("div", {
      "data-tid": StickyDataTids.root,
      ref: this.refWrapper,
      className: styles.wrapper()
    }, /*#__PURE__*/React.createElement(ZIndex, {
      priority: "Sticky",
      applyZIndex: fixed,
      className: cx(styles.inner(), (_cx = {}, _cx[styles.fixed()] = fixed && !stopped, _cx[styles.stopped()] = stopped, _cx)),
      style: innerStyle,
      wrapperRef: this.refInner
    }, /*#__PURE__*/React.createElement("div", {
      className: styles.container()
    }, children)), fixed && !stopped ? /*#__PURE__*/React.createElement("div", {
      style: {
        width: width,
        height: height
      }
    }) : null));
  };
  return Sticky;
}(React.Component), _Sticky.__KONTUR_REACT_UI__ = 'Sticky', _Sticky.displayName = 'Sticky', _Sticky.defaultProps = {
  offset: 0
}, _Sticky)) || _class;