import React, { forwardRef, useEffect, useLayoutEffect, useRef, useState } from "react";
import { css } from "@emotion/react";
import { cx, safeUseId } from "../../utils";
import { useOutsideClick, useForkRef } from "../../hooks";
import { base as sizeCSS } from "./variations/_size/base";
import { base as viewCSS } from "./variations/_view/base";
import { base as disabledCSS } from "./variations/_disabled/base";
import { base as readOnlyCSS } from "./variations/_read-only/base";
import { base as labelPlacementCSS } from "./variations/_label-placement/base";
import { base as hintViewCSS } from "./variations/_hint-view/base";
import { base as hintSizeCSS } from "./variations/_hint-size/base";
import { base as chipViewCSS } from "./variations/_chip-view/base";
import { Input, InputContainer, StyledHelpers, StyledLeftHelper, StyledRightHelper, Label, InputWrapper, InputLabelWrapper, StyledContentLeft, StyledContentRight, StyledChips, StyledTextBefore, StyledTextAfter, StyledIndicator, StyledOptionalText, InputPlaceholder, OuterLabelWrapper, TitleCaption, StyledHintWrapper, StyledIndicatorWrapper, StyledContentRightWrapper, InputPlaceholderValue } from "./TextField.styles";
import { classes } from "./TextField.tokens";
import { TextFieldChip, TextFieldChipNew } from "./ui";
import { useKeyNavigation } from "./hooks";
import { HintComponent } from "./ui/Hint/Hint";
import { getInputWidth } from "./getInputWidth";
export const base = /*#__PURE__*/ css("display:block;", "base");
const HINT_DEFAULT_OFFSET = [
    0,
    0
];
export const textFieldRoot = (Root)=>/*#__PURE__*/ forwardRef(({ id, className, style, // layout
    contentLeft, contentRight, label, labelPlacement, keepPlaceholder, textBefore, textAfter, placeholder, leftHelper, rightHelper, enumerationType = 'plain', requiredPlacement = 'right', hasRequiredIndicator = false, titleCaption, chipView = 'default', chipValidator, // hint
    hintTrigger = 'hover', hintText, hintView = 'default', hintSize = 'm', hintTargetIcon, hintTargetPlacement = 'outer', hintPlacement = 'auto', hintHasArrow, hintOffset = HINT_DEFAULT_OFFSET, hintWidth, hintContentLeft, hintPortal, // variations
    appearance, view, size, readOnly = false, disabled = false, required = false, clear = false, optional, optionalText = 'optional', hasDivider, // controlled
    value: outerValue, chips: values, chipType = 'default', // @ts-ignore
    _chips, // @ts-ignore
    _chipClickArea, // @ts-ignore
    _onChipCloseClick, // events
    onChange, onChangeChips, onSearch, onKeyDown, onFocus, onBlur, onPaste, onScroll, // Пропсы для внутреннего использования, не отдается наружу.
    // @ts-ignore
    _onEnterDisabled, // @ts-ignore
    _forceChipManipulationWithReadonly, /** Внутреннее свойство _interaction_disabled нужно для компонента Select,
                 * в режиме textfield-like, чтобы запретить взаимодействие с компонентом. */ // @ts-ignore
    _interaction_disabled = false, ...rest }, ref)=>{
        const contentRef = useRef(null);
        const inputContainerRef = useRef(null);
        const inputRef = useRef(null);
        const inputForkRef = useForkRef(inputRef, ref);
        const chipsRefs = useRef([]);
        const hintRef = useRef(null);
        const controlledRefs = {
            contentRef,
            inputRef,
            chipsRefs
        };
        const [hasValue, setHasValue] = useState(Boolean(outerValue) || Boolean(inputRef?.current?.value) || Boolean(rest?.defaultValue));
        const [hasFocus, setHasFocus] = useState(false);
        const [chips, setChips] = useState([]);
        const [isHintVisible, setIsHintVisible] = useState(false);
        const uniqId = safeUseId();
        const innerId = id || uniqId;
        const labelId = safeUseId();
        const helperTextId = safeUseId();
        const isChipEnumeration = enumerationType === 'chip';
        const isChipsVisible = isChipEnumeration && Boolean(chips?.length || _chips?.length);
        const withHasChips = isChipsVisible ? classes.hasChips : undefined;
        const hasLabelValue = Boolean(label);
        const hasInnerLabel = size !== 'xs' && labelPlacement === 'inner' && !isChipsVisible && hasLabelValue;
        const hasOuterLabel = labelPlacement === 'outer' && hasLabelValue;
        const innerKeepPlaceholder = keepPlaceholder && labelPlacement === 'inner';
        const hasPlaceholder = Boolean(placeholder) && (innerKeepPlaceholder || !hasInnerLabel);
        let hasTextAfter = Boolean(textAfter);
        let hasTextBefore = textBefore && !isChipEnumeration;
        if (labelPlacement === 'inner') {
            if (!hasValue && !hasPlaceholder && !hasFocus) {
                hasTextAfter = false;
                hasTextBefore = false;
            }
        }
        const hasPlaceholderPadding = hasInnerLabel && keepPlaceholder && size !== 'xs';
        const innerLabelValue = hasInnerLabel || hasOuterLabel ? label : undefined;
        const innerLabelPlacementValue = labelPlacement === 'inner' && !hasInnerLabel ? undefined : labelPlacement;
        const innerPlaceholderValue = hasPlaceholder ? placeholder : undefined;
        const placeholderShown = Boolean(innerPlaceholderValue) && !hasValue;
        const clearClass = clear || appearance === 'clear' ? classes.clear : undefined;
        const hasDividerClass = hasDivider ? classes.hasDivider : undefined;
        const hasInnerHintClass = hintText && hintTargetPlacement === 'outer' ? classes.hasHint : undefined;
        const hasHintClass = hintText ? classes.hasHint : undefined;
        const requiredPlacementClass = requiredPlacement === 'right' ? classes.requiredAlignRight : undefined;
        const labelPlacementClass = innerLabelPlacementValue ? classes[`${innerLabelPlacementValue}LabelPlacement`] : undefined;
        const hasValueClass = hasValue ? classes.hasValue : undefined;
        const keepPlaceholderClass = hasPlaceholder && placeholderShown && classes.keepPlaceholder;
        const wrapperWithoutLeftContent = !contentLeft && isChipsVisible && chipType === 'default' ? classes.hasEmptyContentLeft : undefined;
        const wrapperWithoutRightContent = !contentRight && isChipsVisible && chipType === 'default' ? classes.hasEmptyContentRight : undefined;
        const contentRightCompensationMargin = !hasOuterLabel && hintText && hintTargetPlacement === 'inner' ? classes.contentRightCompensationMargin : undefined;
        useOutsideClick(()=>{
            setIsHintVisible(false);
        }, [
            hintRef
        ]);
        const hintInnerRef = useRef(null);
        const hintForkRef = useForkRef(hintRef, hintInnerRef);
        const handleInput = (event)=>{
            const { value } = event.target;
            setHasValue(Boolean(value));
        };
        const handleFocus = (event)=>{
            setHasFocus(true);
            onFocus?.(event);
        };
        const handleBlur = (event)=>{
            setHasFocus(false);
            event.currentTarget.scrollLeft = 0;
            onBlur?.(event);
        };
        const handleHintShow = ()=>setIsHintVisible(true);
        const handleHintHide = ()=>setIsHintVisible(false);
        const handleHintClick = (event)=>{
            if (!hintText || hintTrigger !== 'click') {
                return;
            }
            event.stopPropagation();
            const targetIsPopover = event.target === hintInnerRef.current;
            const rootHasTarget = hintInnerRef.current?.contains(event.target);
            if (!targetIsPopover && !rootHasTarget) {
                setIsHintVisible(true);
            }
        };
        const handleChange = (event)=>{
            if (disabled || readOnly || _interaction_disabled) {
                return;
            }
            const { maxLength, value } = event.target;
            if (maxLength !== -1 && value.length > maxLength) {
                return;
            }
            if (onChange) {
                onChange(event);
            }
            if (hasTextAfter) {
                const textWidth = getInputWidth(event.currentTarget, inputContainerRef.current);
                event.currentTarget.style.width = `${textWidth}px`;
            }
        };
        const handlePaste = (event)=>{
            if (disabled || readOnly || _interaction_disabled) {
                return;
            }
            if (onPaste) {
                onPaste(event);
            }
            if (hasTextAfter) {
                setTimeout(()=>{
                    if (!inputRef.current) {
                        return;
                    }
                    const textWidth = getInputWidth(inputRef.current, inputContainerRef.current);
                    inputRef.current.style.width = `${textWidth}px`;
                });
            }
        };
        const handleScroll = (e)=>{
            if (!hasFocus && e?.currentTarget) {
                e.currentTarget.scrollLeft = 0;
            }
            if (onScroll) {
                onScroll(e);
            }
        };
        const updateChips = (newChips, newValues)=>{
            setChips(newChips);
            onChangeChips?.(newValues);
        };
        const { handleInputKeydown, handleChipKeyDown, onChipClear, handleContentKeyDown } = useKeyNavigation({
            controlledRefs,
            disabled,
            readOnly,
            chips,
            newCustomChips: _chips,
            enumerationType,
            updateChips,
            onSearch,
            onChange,
            onEnterDisabled: _onEnterDisabled,
            onChipCloseClick: _onChipCloseClick,
            _interaction_disabled
        });
        const onChipClick = (event)=>event.stopPropagation();
        const handleInputFocus = ()=>{
            if (readOnly || disabled || !inputRef?.current || _interaction_disabled) {
                return;
            }
            inputRef.current.focus();
        };
        const getRef = (element, index)=>{
            if (element && chipsRefs?.current) {
                chipsRefs.current[index] = element;
            }
        };
        const handleOnKeyDown = (event)=>{
            handleInputKeydown(event);
            if (onKeyDown) {
                onKeyDown(event);
            }
        };
        useEffect(()=>{
            if (hasTextAfter && inputRef.current) {
                const textWidth = getInputWidth(inputRef.current, inputContainerRef.current);
                inputRef.current.style.width = `${textWidth}px`;
            } else {
                inputRef.current?.style.removeProperty('width');
            }
        }, [
            hasTextAfter,
            outerValue
        ]);
        useEffect(()=>{
            if (!isChipEnumeration && !values?.length) {
                return;
            }
            const newChips = values?.map((value, index)=>({
                    id: `${index}_${value}`,
                    text: value
                })) || [];
            setChips(newChips);
        }, [
            isChipEnumeration,
            values
        ]);
        useEffect(()=>{
            setHasValue(Boolean(rest?.defaultValue));
        }, [
            rest.defaultValue
        ]);
        useEffect(()=>{
            setHasValue(Boolean(outerValue) || Boolean(inputRef?.current?.value));
        }, [
            outerValue,
            inputRef?.current?.value
        ]);
        useLayoutEffect(()=>{
            if (!hasFocus && inputRef.current) {
                inputRef.current.scrollLeft = 0;
            }
        }, [
            hasFocus
        ]);
        const innerOptional = Boolean(required ? false : optional);
        const hasPlaceholderOptional = innerOptional && !innerLabelValue && !hasOuterLabel;
        const optionalTextNode = innerOptional ? /*#__PURE__*/ React.createElement(StyledOptionalText, null, Boolean(hasPlaceholderOptional ? innerPlaceholderValue : innerLabelValue) && '\xa0', optionalText) : null;
        const classTextEllipsis = // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        // eslint-disable-next-line no-underscore-dangle
        !rest._textEllipsisDisable && !textAfter && !hasFocus ? classes.inputTextEllipsis : undefined;
        return /*#__PURE__*/ React.createElement(Root, {
            view: view,
            size: size,
            disabled: disabled,
            readOnly: !disabled && readOnly,
            labelPlacement: innerLabelPlacementValue,
            onClick: handleInputFocus,
            "data-root": true,
            className: cx(labelPlacementClass, clearClass, hasDividerClass, hasInnerHintClass, classes.textFieldGroupItem, className),
            style: style,
            ...hintText && {
                hintView,
                hintSize
            }
        }, (hasOuterLabel || titleCaption) && /*#__PURE__*/ React.createElement(OuterLabelWrapper, {
            isInnerLabel: labelPlacement === 'inner'
        }, hasOuterLabel && /*#__PURE__*/ React.createElement(StyledIndicatorWrapper, null, /*#__PURE__*/ React.createElement(Label, {
            id: labelId,
            htmlFor: id
        }, innerLabelValue), hintText && /*#__PURE__*/ React.createElement(StyledHintWrapper, null, /*#__PURE__*/ React.createElement(HintComponent, {
            ref: hintForkRef,
            hintText: hintText,
            hintTrigger: hintTrigger,
            isHintVisible: isHintVisible,
            hintTargetIcon: hintTargetIcon,
            hintPlacement: hintPlacement,
            hintHasArrow: hintHasArrow,
            hintOffset: hintOffset,
            hintWidth: hintWidth,
            hintPortal: hintPortal,
            hintContentLeft: hintContentLeft,
            handleHintShow: handleHintShow,
            handleHintHide: handleHintHide,
            handleHintClick: handleHintClick
        })), required && hasRequiredIndicator && /*#__PURE__*/ React.createElement(StyledIndicator, {
            className: cx(classes.outerLabelPlacement, requiredPlacementClass, hasHintClass)
        }), optionalTextNode), titleCaption && /*#__PURE__*/ React.createElement(TitleCaption, {
            "data-root": true
        }, titleCaption)), /*#__PURE__*/ React.createElement(InputWrapper, {
            // Ref для внутреннего использования. Не отдается наружу.
            ref: rest.inputWrapperRef,
            className: cx(withHasChips, wrapperWithoutLeftContent, wrapperWithoutRightContent, classes.inputWrapper)
        }, !hasOuterLabel && /*#__PURE__*/ React.createElement(React.Fragment, null, required && hasRequiredIndicator && /*#__PURE__*/ React.createElement(StyledIndicator, {
            className: cx(classes.innerLabelPlacement, requiredPlacementClass)
        }), hintText && hintTargetPlacement === 'outer' && /*#__PURE__*/ React.createElement(StyledHintWrapper, {
            className: classes.innerLabelPlacement
        }, /*#__PURE__*/ React.createElement(HintComponent, {
            ref: hintForkRef,
            hintText: hintText,
            hintTrigger: hintTrigger,
            isHintVisible: isHintVisible,
            hintTargetIcon: hintTargetIcon,
            hintPlacement: hintPlacement,
            hintHasArrow: hintHasArrow,
            hintOffset: hintOffset,
            hintWidth: hintWidth,
            hintPortal: hintPortal,
            hintContentLeft: hintContentLeft,
            size: size,
            handleHintShow: handleHintShow,
            handleHintHide: handleHintHide,
            handleHintClick: handleHintClick,
            isInnerLabel: true
        }))), contentLeft && /*#__PURE__*/ React.createElement(StyledContentLeft, {
            "data-root": true
        }, contentLeft), /*#__PURE__*/ React.createElement(InputLabelWrapper, {
            tabIndex: -1,
            ref: contentRef,
            onKeyDown: handleContentKeyDown,
            className: cx(withHasChips, classes.inputScrollableWrapper)
        }, Boolean(textBefore && isChipEnumeration) && /*#__PURE__*/ React.createElement(StyledTextBefore, null, textBefore), Boolean(_chips?.length) && /*#__PURE__*/ React.createElement(TextFieldChipNew, {
            chips: _chips,
            getRef: getRef,
            handleChipKeyDown: handleChipKeyDown,
            onChipClear: onChipClear,
            onChipCloseClick: _onChipCloseClick,
            chipClickArea: _chipClickArea,
            view: chipView || view,
            readOnly: readOnly,
            chipType: chipType,
            // TODO: #1547
            // @ts-ignore
            _forceChipManipulationWithReadonly: _forceChipManipulationWithReadonly
        }), isChipEnumeration && Boolean(chips?.length) && /*#__PURE__*/ React.createElement(StyledChips, {
            className: classes.chipsWrapper
        }, chips?.map(({ id: chipId, text }, index)=>{
            const validationView = chipValidator?.(String(text));
            const resView = validationView?.view || chipView;
            return /*#__PURE__*/ React.createElement(TextFieldChip, {
                id: chipId,
                ref: (element)=>getRef(element, index),
                key: `${chipId}_${index}`,
                disabled: disabled,
                readOnly: readOnly,
                value: text,
                text: text,
                onKeyDown: (event)=>handleChipKeyDown(event, chipId, index),
                onClear: ()=>onChipClear(chipId, index),
                onClick: onChipClick,
                chipType: chipType,
                view: resView,
                rootWrapper: Root,
                // TODO: #1547
                // @ts-ignore
                _forceChipManipulationWithReadonly: _forceChipManipulationWithReadonly
            });
        })), /*#__PURE__*/ React.createElement(InputContainer, {
            ref: inputContainerRef,
            hasDynamicWidth: hasTextAfter
        }, hasTextBefore && /*#__PURE__*/ React.createElement(StyledTextBefore, null, textBefore), /*#__PURE__*/ React.createElement(Input, {
            ref: inputForkRef,
            id: innerId,
            value: outerValue,
            required: enumerationType === 'chip' ? chips.length === 0 && required : required,
            "aria-labelledby": labelId,
            "aria-describedby": helperTextId,
            placeholder: innerPlaceholderValue,
            hasFocus: hasFocus,
            className: cx(hasValueClass, keepPlaceholderClass, classTextEllipsis, readOnly && classes.readOnlyInput),
            disabled: disabled,
            readOnly: !disabled && (readOnly || _interaction_disabled),
            onInput: handleInput,
            onChange: handleChange,
            onKeyDown: handleOnKeyDown,
            onFocus: handleFocus,
            onBlur: handleBlur,
            onPaste: handlePaste,
            onScroll: handleScroll,
            ...rest
        }), hasInnerLabel && /*#__PURE__*/ React.createElement(Label, {
            "data-root": true,
            id: labelId,
            htmlFor: innerId
        }, /*#__PURE__*/ React.createElement(InputPlaceholderValue, {
            className: cx(classTextEllipsis)
        }, innerLabelValue), optionalTextNode), placeholderShown && !hasValue && /*#__PURE__*/ React.createElement(InputPlaceholder, {
            hasPadding: hasPlaceholderPadding
        }, hasTextBefore && /*#__PURE__*/ React.createElement(StyledTextBefore, {
            isHidden: true
        }, textBefore), innerPlaceholderValue && /*#__PURE__*/ React.createElement(InputPlaceholderValue, {
            className: cx(classTextEllipsis)
        }, innerPlaceholderValue), hasPlaceholderOptional && optionalTextNode), hasTextAfter && /*#__PURE__*/ React.createElement(StyledTextAfter, null, textAfter))), /*#__PURE__*/ React.createElement(StyledContentRightWrapper, {
            className: cx(contentRightCompensationMargin)
        }, contentRight && /*#__PURE__*/ React.createElement(StyledContentRight, {
            "data-root": true
        }, contentRight), !hasOuterLabel && hintText && hintTargetPlacement === 'inner' && /*#__PURE__*/ React.createElement(HintComponent, {
            ref: hintForkRef,
            hintText: hintText,
            hintTrigger: hintTrigger,
            isHintVisible: isHintVisible,
            hintTargetIcon: hintTargetIcon,
            hintPlacement: hintPlacement,
            hintHasArrow: hintHasArrow,
            hintOffset: hintOffset,
            hintWidth: hintWidth,
            hintPortal: hintPortal,
            hintContentLeft: hintContentLeft,
            size: size,
            handleHintShow: handleHintShow,
            handleHintHide: handleHintHide,
            handleHintClick: handleHintClick,
            isInnerLabel: true
        }))), (leftHelper || rightHelper) && /*#__PURE__*/ React.createElement(StyledHelpers, {
            id: helperTextId,
            className: hasFocus ? classes.hasFocus : undefined
        }, leftHelper && /*#__PURE__*/ React.createElement(StyledLeftHelper, {
            "data-root": true
        }, leftHelper), rightHelper && /*#__PURE__*/ React.createElement(StyledRightHelper, {
            "data-root": true
        }, rightHelper)));
    });
export const textFieldConfig = {
    name: 'TextField',
    tag: 'div',
    layout: textFieldRoot,
    base,
    variations: {
        view: {
            css: viewCSS
        },
        size: {
            css: sizeCSS
        },
        disabled: {
            css: disabledCSS,
            attrs: true
        },
        readOnly: {
            css: readOnlyCSS,
            attrs: true
        },
        labelPlacement: {
            css: labelPlacementCSS
        },
        hintView: {
            css: hintViewCSS
        },
        hintSize: {
            css: hintSizeCSS
        },
        chipView: {
            css: chipViewCSS
        }
    },
    defaults: {
        size: 'm',
        view: 'default'
    }
};
