/**
 * @license MIT
 * author: Cube Dev Team
 * @cube-dev/ui-kit v0.0.0-canary-7eefd09
 * Released under the MIT license.
 */

import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useEffect, useMemo, useRef, useState, } from 'react';
import { useEvent } from '../../../_internal/hooks/index.js';
import { CloseIcon, PlusIcon } from '../../../icons/index.js';
import { mergeProps, useCombinedRefs } from '../../../utils/react/index.js';
import { Button } from '../../actions/index.js';
import { Block } from '../../Block.js';
import { useFieldProps, useFormProps, wrapWithField } from '../../form/index.js';
import { Flow } from '../../layout/Flow.js';
import { Grid } from '../../layout/Grid.js';
import { Space } from '../../layout/Space.js';
import { ComboBox } from '../ComboBox/index.js';
import { PasswordInput } from '../PasswordInput/PasswordInput.js';
import { TextArea } from '../TextArea/index.js';
import { TextInput } from '../TextInput/index.js';
// Rewrites upper level field component styles
// @TODO: Remove this after the release of new Element API
const PROPS_GRID_HACK = {
    styles: {
        InputArea: {
            gridColumn: {
                '': 'auto',
                'has-sider': 'auto',
            },
        },
    },
};
// remove duplicates in mappings
function removeDuplicates(mappings) {
    const keys = new Set();
    return mappings.filter(({ key }) => {
        if (keys.has(key)) {
            return false;
        }
        keys.add(key);
        return true;
    });
}
function TextInputMapper(props, ref) {
    ref = useCombinedRefs(ref);
    props = useFormProps(props);
    props = useFieldProps(props, {
        defaultValidationTrigger: 'onChange',
        valuePropsMapper: ({ value, onChange }) => ({
            value: value != null ? value : {},
            onChange: onChange,
        }),
    });
    const counterRef = useRef(0);
    let { qa, isDisabled, actionLabel, value, onChange, keyProps, valueProps, KeyComponent, ValueComponent, size = 'medium', form, } = props;
    function extractLocalValues(value, localValues) {
        const valueKeys = Object.keys(value);
        const localKeys = localValues.map(({ key }) => key);
        localKeys.forEach((key) => {
            if (!valueKeys.includes(key) && key !== '') {
                localValues = localValues.filter(({ key: k }) => k !== key);
            }
        });
        Object.entries(value ?? {}).forEach(([key, value]) => {
            const exist = localValues.find(({ key: k }) => k === key);
            if (exist) {
                exist.value = value;
            }
            else {
                localValues.push({ key, value, id: counterRef.current++ });
            }
        });
        return removeDuplicates(localValues);
    }
    const [mappings, setMappings] = useState(() => {
        return extractLocalValues(value ?? {}, []);
    });
    useEffect(() => {
        setMappings(extractLocalValues(value ?? {}, mappings));
    }, [JSON.stringify(value)]);
    const onMappingsChange = useEvent((newMappings) => {
        const newValue = newMappings.reduce((acc, { key, value }) => {
            acc[key.trim()] = value.trim();
            return acc;
        }, {});
        const keys = Object.keys(newValue);
        if (!keys.length) {
            onChange?.(undefined);
        }
        else {
            onChange?.(newValue);
        }
        const updatedMappings = extractLocalValues(newValue ?? {}, newMappings);
        if (JSON.stringify(updatedMappings) !== JSON.stringify(mappings)) {
            setMappings(updatedMappings);
        }
    });
    // useEffect(() => {
    //   // focus on the last non-disabled input
    //   setTimeout(() => {
    //     (
    //       ref?.current?.querySelector(
    //         '[data-qa="Mapping"]:last-child input:not([disabled])',
    //       ) as HTMLInputElement
    //     )?.focus();
    //   }, 100);
    // }, [mappings.length]);
    const addNewMapping = useEvent(() => {
        setMappings((prev) => {
            return [...prev, { key: '', value: '', id: counterRef.current++ }];
        });
    });
    const showNewButton = useMemo(() => {
        return (!mappings.length || !mappings.some(({ key, value }) => !key || !value));
    }, [mappings]);
    KeyComponent = KeyComponent ?? TextInputMapperInput;
    ValueComponent = ValueComponent ?? TextInputMapperInput;
    const onKeyChange = useEvent((id, value) => {
        mappings.forEach((mapping) => {
            if (mapping.id === id) {
                mapping.key = value;
            }
        });
        setMappings([...mappings]);
    });
    const onValueChange = useEvent((id, value) => {
        mappings.forEach((mapping) => {
            if (mapping.id === id) {
                mapping.value = value;
            }
        });
        setMappings([...mappings]);
    });
    const onSubmit = useEvent(() => {
        onMappingsChange(mappings);
    });
    const onKeyDown = useEvent((e) => {
        // if Ctrl+Enter or Cmd+Enter is pressed then add new mapping if that's enabled
        if ((e.ctrlKey || e.metaKey) && e.key === 'Enter' && showNewButton) {
            addNewMapping();
        }
    });
    const renderedMappings = useMemo(() => {
        return mappings.map((mapping, index) => {
            const { key, value, id } = mapping;
            return (_jsxs(Grid, { qa: "Mapping", columns: "minmax(0, 1fr) minmax(0, 1fr) min-content", gap: "1x", children: [_jsx(KeyComponent, { autoFocus: index === mappings.length - 1, id: id, isDisabled: isDisabled, fieldType: "key", value: key, placeholder: "Key", size: size, onChange: onKeyChange, onSubmit: onSubmit, ...keyProps }), _jsx(ValueComponent, { id: id, fieldType: "value", isDisabled: !key || isDisabled, value: value, placeholder: "Value", size: size, onChange: onValueChange, onSubmit: onSubmit, ...valueProps }), _jsx(Button, { "aria-label": "Remove mapping", theme: "danger", type: "clear", size: size, icon: _jsx(CloseIcon, {}), onPress: () => {
                            setMappings(mappings.filter((m) => m.id !== id));
                            onMappingsChange(mappings.filter((m) => m.id !== id));
                        } })] }, id));
        });
    }, [JSON.stringify(mappings)]);
    const element = (_jsxs(Flow, { ref: ref, gap: "1x", "data-qa": qa || 'TextInputMapper', "data-input-type": "textinputmapper", onKeyDown: onKeyDown, children: [[...renderedMappings], showNewButton ? (_jsxs(Space, { gap: 0, children: [_jsx(Block, { styles: { overflow: 'clip', width: 'max 0px' }, children: "\u00A0" }), _jsx(Button, { isDisabled: isDisabled, size: size, icon: _jsx(PlusIcon, {}), onPress: addNewMapping, children: actionLabel ? actionLabel : 'Mapping' })] })) : null] }));
    return wrapWithField(element, ref, props);
}
function TextInputMapperInput(props) {
    const { id, fieldType, inputType = 'input', options, value, size = 'medium', placeholder, allowsCustomValue, ...rest } = props;
    const onChange = useEvent((newValue) => {
        props.onChange?.(id, newValue);
    });
    const onBlur = useEvent(() => {
        props.onSubmit?.(id);
    });
    const onSelectionChange = useEvent((newValue) => {
        if (!allowsCustomValue && !options?.includes(newValue)) {
            props.onChange?.(id, '');
        }
        else {
            props.onChange?.(id, newValue);
        }
        props.onSubmit?.(id);
    });
    const Component = {
        input: TextInput,
        textarea: TextArea,
        password: PasswordInput,
    }[inputType];
    if (inputType === 'combobox') {
        return (_jsx(ComboBox, { qa: "AddMapping", "data-type": fieldType, width: "auto", size: size, ...mergeProps(rest, PROPS_GRID_HACK), id: undefined, inputValue: value, selectedKey: value, labelPosition: "top", "aria-label": placeholder, placeholder: placeholder, allowsCustomValue: allowsCustomValue, onInputChange: onChange, onSelectionChange: (val) => onSelectionChange(val ?? ''), children: (options ?? []).map((option) => (_jsx(ComboBox.Item, { children: option }, option))) }));
    }
    return (_jsx(Component, { qa: "AddMapping", "data-type": fieldType, width: "auto", rows: 1, size: size, ...mergeProps(rest, PROPS_GRID_HACK), id: undefined, value: value, labelPosition: "top", "aria-label": placeholder, placeholder: placeholder, onChange: onChange, onBlur: onBlur }));
}
const _TextInputMapper = forwardRef(TextInputMapper);
_TextInputMapper.displayName = 'TextInputMapper';
export { _TextInputMapper as TextInputMapper };

        