"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutocompleteFooter = exports.AutocompleteOption = exports.AutocompleteOptions = exports.Autocomplete = void 0;
const react_1 = __importStar(require("react"));
const css_utilities_1 = require("@shopify/css-utilities");
const TextField_1 = require("../TextField");
const Theme_1 = require("../Theme");
const Popper_1 = require("../Popper");
const Icon_1 = require("../Icon");
const focus_1 = require("../../utilities/focus");
const Autocomplete_css_1 = __importDefault(require("./Autocomplete.css"));
function Autocomplete({ error, id, label, name, onInput, onChange, options, onSelectOption, value, ariaLabel, title, children, required, autocomplete, disabled, readonly, }) {
    const [open, setOpen] = react_1.useState(false);
    const [selected, setSelected] = react_1.useState(0);
    const fieldRef = react_1.useRef(null);
    const popperRef = react_1.useRef(null);
    const closeButtonRef = react_1.useRef(null);
    const { controls: { background: controlsBackground }, textFields: { background: textFieldsBackground }, } = Theme_1.useThemeConfiguration();
    const background = textFieldsBackground || controlsBackground || 'surfaceTertiary';
    const handleOpen = () => {
        if (open) {
            return;
        }
        if (options.length === 0) {
            return;
        }
        // Prevents opening the autocomplete when the address field is filled
        // via browser autofill.
        if (fieldRef.current == null || !focus_1.isFocused(fieldRef.current))
            return;
        setOpen(true);
    };
    const handleClose = react_1.useCallback(() => {
        if (!open) {
            return;
        }
        setOpen(false);
    }, [open]);
    const handleInput = (newValue) => {
        if (newValue === '') {
            handleClose();
        }
        else {
            handleOpen();
        }
        onInput === null || onInput === void 0 ? void 0 : onInput(newValue);
    };
    const handleOptionMouseOver = (index) => {
        setSelected(index);
    };
    const handleOptionMouseDown = (index) => {
        handleClose();
        if (onSelectOption) {
            onSelectOption(options[index]);
        }
    };
    const changeSelectedOption = (diff) => {
        if (!open) {
            return;
        }
        setSelected((selected) => {
            if (selected + diff >= options.length) {
                return 0;
            }
            else if (selected + diff < 0) {
                return options.length - 1;
            }
            return selected + diff;
        });
    };
    const handleKeyDown = (event) => {
        switch (event.key) {
            case 'ArrowDown':
            case 'Down':
                // Prevent cursor move
                event.preventDefault();
                changeSelectedOption(1);
                handleOpen();
                break;
            case 'ArrowUp':
            case 'Up':
                // Prevent cursor move
                event.preventDefault();
                changeSelectedOption(-1);
                handleOpen();
                break;
            case 'Enter':
                if (open) {
                    // Prevent form validation
                    event.preventDefault();
                    handleClose();
                    if (onSelectOption) {
                        onSelectOption(options[selected]);
                    }
                }
                else {
                    onChange === null || onChange === void 0 ? void 0 : onChange(event.currentTarget.value);
                }
                break;
            case 'Escape':
            case 'Esc':
                if (open) {
                    handleClose();
                }
                break;
            case 'Tab':
                if (event.shiftKey) {
                    handleClose();
                }
                else if (closeButtonRef.current) {
                    closeButtonRef.current.focus();
                    event.preventDefault();
                }
                break;
        }
    };
    const autocompleteOptions = react_1.default.Children.map(children, (child) => {
        if (react_1.default.isValidElement(child) && child.type === AutocompleteOptions) {
            return react_1.default.cloneElement(child, { id: `${id}-options` }, react_1.default.Children.toArray(child.props.children).map((child, index) => {
                if (typeof child === 'object' &&
                    'type' in child &&
                    child.type === AutocompleteOption) {
                    return react_1.default.cloneElement(child, {
                        id: `${id}-option-${index}`,
                        isSelected: selected === index,
                        onMouseDown: () => {
                            var _a;
                            handleOptionMouseDown(index);
                            (_a = fieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                        },
                        onMouseOver: () => handleOptionMouseOver(index),
                    });
                }
            }));
        }
    });
    react_1.useEffect(() => {
        const handleClickOutside = (event) => {
            var _a, _b, _c;
            if (event.target instanceof Node &&
                !((_a = fieldRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target)) &&
                !((_b = popperRef.current) === null || _b === void 0 ? void 0 : _b.contains(event.target))) {
                handleClose();
            }
            else if (event.target !== fieldRef.current) {
                (_c = fieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
            }
        };
        document.addEventListener('click', handleClickOutside);
        return () => {
            document.removeEventListener('click', handleClickOutside);
        };
    }, [handleClose]);
    react_1.useEffect(() => {
        if (options.length === 0) {
            // Prevents the loss of focus
            if (open && fieldRef.current && !focus_1.isFocused(fieldRef.current)) {
                fieldRef.current.focus();
            }
        }
        else if (!open && fieldRef.current && focus_1.isFocused(fieldRef.current)) {
            handleOpen();
        }
    }, 
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [options.length]);
    const autocompleteFooter = react_1.default.Children.map(children, (child) => {
        if (react_1.default.isValidElement(child) && child.type === AutocompleteFooter) {
            return child;
        }
    });
    const fieldFocused = Boolean(fieldRef.current && focus_1.isFocused(fieldRef.current));
    const closeButtonFocused = Boolean(closeButtonRef.current && focus_1.isFocused(closeButtonRef.current));
    const renderPopper = open && options.length > 0 && (fieldFocused || closeButtonFocused);
    const autocompleteClassName = css_utilities_1.classNames(Autocomplete_css_1.default.Autocomplete, background && Autocomplete_css_1.default[css_utilities_1.variationName('background', background)]);
    return (<>
      <TextField_1.TextFieldInternal label={label} ariaActiveDescendant={open ? `${id}-option-${selected}` : undefined} ariaAutocomplete="list" ariaControls={`${id}-options`} ariaExpanded={renderPopper} required={required} autocomplete={!open && autocomplete} error={error} id={id} name={name} onInput={handleInput} onChange={onChange} onFocus={handleOpen} onKeyDown={handleKeyDown} ref={fieldRef} role="combobox" controlledValue={value} disabled={disabled} readonly={readonly}/>
      {renderPopper && (<Popper_1.Popper activator={fieldRef.current} sameInlineSize minInlineSize={320} preventOverflow placement="blockEnd" offset={7}>
          <div className={autocompleteClassName} ref={popperRef}>
            <div className={Autocomplete_css_1.default.Header}>
              <h3 className={Autocomplete_css_1.default.Title}>{title}</h3>
              <button type="button" className={Autocomplete_css_1.default.Close} onClick={() => {
        var _a;
        handleClose();
        (_a = fieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }} onKeyDown={(event) => {
        var _a, _b;
        if (event.key === 'Tab') {
            if (event.shiftKey) {
                (_a = fieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                event.preventDefault();
            }
            else {
                handleClose();
                (_b = fieldRef.current) === null || _b === void 0 ? void 0 : _b.focus();
            }
        }
    }} ref={closeButtonRef}>
                <Icon_1.Icon size="base" source="close" appearance="subdued" accessibilityLabel={ariaLabel}/>
              </button>
            </div>
            {autocompleteOptions}
            {autocompleteFooter}
          </div>
        </Popper_1.Popper>)}
    </>);
}
exports.Autocomplete = Autocomplete;
function AutocompleteOptions({ children, id }) {
    return (<ul className={Autocomplete_css_1.default.Options} id={id} onMouseDown={(event) => {
        // Prevent blur
        event.preventDefault();
    }} 
    // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
    role="listbox">
      {children}
    </ul>);
}
exports.AutocompleteOptions = AutocompleteOptions;
function AutocompleteOption({ children, id, isSelected, onMouseDown, onMouseOver, }) {
    return (
    // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
    <li aria-selected={isSelected} className={css_utilities_1.classNames(Autocomplete_css_1.default.Option, {
        [Autocomplete_css_1.default.selected]: isSelected,
    })} id={id} onMouseDown={onMouseDown} onMouseOver={onMouseOver} 
    // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
    role="option">
      {children}
    </li>);
}
exports.AutocompleteOption = AutocompleteOption;
function AutocompleteFooter({ children }) {
    return <div className={Autocomplete_css_1.default.Footer}>{children}</div>;
}
exports.AutocompleteFooter = AutocompleteFooter;
