import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
var _excluded = ["children", "onInput", "onFocus", "onBlur", "showOnFocus", "alwaysShowMask"]; /* eslint react-hooks/exhaustive-deps: 2 */

import React, { useEffect, useContext, useImperativeHandle, useRef, useCallback, useState } from 'react';
import debounce from 'lodash.debounce';
import { ThemeContext } from "../../../../lib/theming/ThemeContext";
import { forwardRefAndName } from "../../../../lib/forwardRefAndName";
import { cx } from "../../../../lib/theming/Emotion";
import { isDocument, isWindow, tryGetDocument, tryGetWindow } from "../../../../lib/utils";
import { globalClasses } from "../ColorableInputElement.styles";

// Возможно придётся включить.
// Иногда, на тяжёлых страницах, текст рендерится итеративно.
// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.
// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);

export var ColorableInputElement = forwardRefAndName('ColorableInputElement', function ColorableInputElement(props, ref) {
  var _props$style3;
  var inputRef = useRef(null);
  var spanRef = useRef(null);
  var focused = useRef(false);
  var updateActiveTimer = useRef();
  var theme = useContext(ThemeContext);
  var _useState = useState(Boolean(props.alwaysShowMask || !props.placeholder && (props.value || props.defaultValue))),
    active = _useState[0],
    setActive = _useState[1];
  var children = props.children,
    onInput = props.onInput,
    onFocus = props.onFocus,
    onBlur = props.onBlur,
    showOnFocus = props.showOnFocus,
    alwaysShowMask = props.alwaysShowMask,
    inputProps = _objectWithoutPropertiesLoose(props, _excluded);
  var stopUpdateActive = useCallback(function () {
    clearTimeout(updateActiveTimer.current);
  }, []);
  var updateActive = useCallback(function () {
    stopUpdateActive();
    updateActiveTimer.current = setTimeout(function () {
      var nextActive = true;
      if (inputRef.current) {
        var _inputRef$current2;
        var _inputRef$current = inputRef.current,
          clientWidth = _inputRef$current.clientWidth,
          scrollWidth = _inputRef$current.scrollWidth;
        var scrollable = scrollWidth > clientWidth;
        var placeholderShown = (_inputRef$current2 = inputRef.current) == null || (_inputRef$current2 = _inputRef$current2.parentElement) == null ? void 0 : _inputRef$current2.querySelector(':placeholder-shown');
        nextActive = !(scrollable || placeholderShown);
      }
      setActive(nextActive);
    }, 0);
  }, [stopUpdateActive]);
  var paintText = useCallback(function () {
    var _inputRef$current4, _shadow, _shadow2, _props$style, _props$style2;
    var win = tryGetWindow(inputRef.current);
    var doc = tryGetDocument(inputRef.current);
    if (!spanRef.current || !inputRef.current || !isWindow(win) || !isDocument(doc) || !active) {
      var _inputRef$current3;
      inputRef.current && (inputRef.current.style.backgroundImage = '');
      (_inputRef$current3 = inputRef.current) == null || _inputRef$current3.classList.remove(globalClasses.input);
      return;
    }
    (_inputRef$current4 = inputRef.current) == null || _inputRef$current4.classList.add(globalClasses.input);
    var shadow = spanRef.current.shadowRoot;
    var typedValueElement = (_shadow = shadow) == null ? void 0 : _shadow.getElementById('typed-value');
    var fullValueElement = (_shadow2 = shadow) == null ? void 0 : _shadow2.getElementById('full-value');
    if (!typedValueElement || !fullValueElement) {
      shadow = spanRef.current.attachShadow({
        mode: 'open'
      });
      typedValueElement = doc.createElement('span');
      fullValueElement = doc.createElement('span');
      typedValueElement.setAttribute('id', 'typed-value');
      fullValueElement.setAttribute('id', 'full-value');
      shadow.append(typedValueElement, fullValueElement);
    }
    var style = getComputedStyle(inputRef.current);
    typedValueElement.textContent = (inputRef.current.getAttribute('data-unmasked-value') || focused.current) && inputRef.current.getAttribute('data-typed-value') || '';
    fullValueElement.textContent = inputRef.current.value || inputRef.current.defaultValue || '';
    var inputRect = inputRef.current.getBoundingClientRect();
    var typedValueRect = typedValueElement.getBoundingClientRect();
    var fullValueRect = fullValueElement.getBoundingClientRect();
    var threshold = typedValueRect.width / (inputRect.width / 100);
    var degree = style.fontStyle === 'italic' ? 100 : 90;
    var restValueWidth = 1 - Math.min(fullValueRect.width / inputRect.width, 1);
    var typedValueColor = theme.inputTextColor;
    var maskColor = theme.inputPlaceholderColor;
    var indent = 0;
    if (props.disabled) {
      typedValueColor = theme.inputTextColorDisabled;
      maskColor = theme.inputTextColorDisabled;
    }
    if (props.showOnFocus) {
      maskColor = focused.current ? maskColor : 'transparent';
    }
    if (((_props$style = props.style) == null ? void 0 : _props$style.textAlign) === 'right') {
      indent = 100 * restValueWidth;
    }
    if (((_props$style2 = props.style) == null ? void 0 : _props$style2.textAlign) === 'center') {
      indent = 50 * restValueWidth;
    }
    inputRef.current.style.backgroundImage = "\n      linear-gradient(\n          " + degree + "deg,\n          " + typedValueColor + " " + (threshold + indent) + "%,\n          " + maskColor + " " + (threshold + indent) + "%\n      )";
  }, [active, props.showOnFocus, props.disabled, theme.inputTextColor, theme.inputPlaceholderColor, theme.inputTextColorDisabled, (_props$style3 = props.style) == null ? void 0 : _props$style3.textAlign]);
  var debouncedPaintText = useCallback(function () {
    return debounce(paintText);
  }, [paintText])();
  var handleInput = useCallback(function (e) {
    debouncedPaintText();
    onInput == null || onInput(e);
  }, [debouncedPaintText, onInput]);
  var handleFocus = useCallback(function (e) {
    updateActive();
    focused.current = true;
    onFocus == null || onFocus(e);
  }, [onFocus, updateActive]);
  var handleBlur = useCallback(function (e) {
    updateActive();
    focused.current = false;
    onBlur == null || onBlur(e);
  }, [onBlur, updateActive]);
  useImperativeHandle(ref, function () {
    return {
      input: inputRef.current,
      getRootNode: function getRootNode() {
        return inputRef.current;
      }
    };
  }, []);
  useEffect(function () {
    debouncedPaintText();
    updateActive();
    return stopUpdateActive;
  }, [updateActive, props.value, props.defaultValue, theme, debouncedPaintText, stopUpdateActive]);
  return /*#__PURE__*/(
    React.createElement(React.Fragment, null, /*#__PURE__*/
    React.cloneElement(children, _extends({}, inputProps, {
      onInput: handleInput,
      onFocus: handleFocus,
      onBlur: handleBlur,
      inputRef: inputRef,
      className: cx(props.className, active && globalClasses.input)
    })), active && /*#__PURE__*/React.createElement("span", {
      style: {
        visibility: 'hidden',
        position: 'absolute',
        whiteSpace: 'pre'
      },
      ref: spanRef
    }))
  );
});