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

import { createElement, forwardRef, useMemo, } from 'react';
import { isValidElementType } from 'react-is';
import { useGlobalStyles } from './hooks/useGlobalStyles';
import { useStyles } from './hooks/useStyles';
import { BASE_STYLES } from './styles/list';
import { getDisplayName } from './utils/getDisplayName';
import { mergeStyles } from './utils/mergeStyles';
import { modAttrs } from './utils/modAttrs';
import { processTokens, stringifyTokens } from './utils/processTokens';
/**
 * Mapping of is* properties to their corresponding HTML attributes
 */
const IS_PROPERTIES_MAP = {
    isDisabled: 'disabled',
    isHidden: 'hidden',
    isChecked: 'checked',
};
/**
 * Precalculated entries for performance optimization
 */
const IS_PROPERTIES_ENTRIES = Object.entries(IS_PROPERTIES_MAP);
/**
 * Helper function to handle is* properties consistently
 * Transforms is* props to HTML attributes and adds corresponding data-* attributes
 */
function handleIsProperties(props) {
    for (const [isProperty, targetAttribute] of IS_PROPERTIES_ENTRIES) {
        if (isProperty in props) {
            props[targetAttribute] = props[isProperty];
            delete props[isProperty];
        }
        // Add data-* attribute if target attribute is truthy and doesn't already exist
        const dataAttribute = `data-${targetAttribute}`;
        if (!(dataAttribute in props) && props[targetAttribute]) {
            props[dataAttribute] = '';
        }
    }
}
// Implementation
export function tasty(Component, options) {
    if (typeof Component === 'string') {
        return tastyGlobal(Component, options);
    }
    if (isValidElementType(Component)) {
        return tastyWrap(Component, options);
    }
    return tastyElement(Component);
}
// Internal specialized implementations
function tastyGlobal(selector, styles) {
    const _StyleDeclarationComponent = () => {
        useGlobalStyles({ selector, styles });
        return null;
    };
    _StyleDeclarationComponent.displayName = `TastyStyleDeclaration(${selector})`;
    return _StyleDeclarationComponent;
}
function tastyWrap(Component, options) {
    let { as: extendTag, element: extendElement, ...defaultProps } = (options ?? {});
    let propsWithStyles = ['styles'].concat(Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')));
    const _WrappedComponent = forwardRef((props, ref) => {
        const { as, element, ...restProps } = props;
        const propsWithStylesValues = propsWithStyles.map((prop) => props[prop]);
        const mergedStylesMap = useMemo(() => {
            return propsWithStyles.reduce((map, prop) => {
                const restValue = restProps[prop];
                const defaultValue = defaultProps[prop];
                if (restValue != null && defaultValue != null) {
                    map[prop] = mergeStyles(defaultValue, restValue);
                }
                else {
                    map[prop] = restValue ?? defaultValue;
                }
                return map;
            }, {});
        }, [propsWithStylesValues]);
        const elementProps = {
            ...defaultProps,
            ...restProps,
            ...mergedStylesMap,
            as: as ?? extendTag,
            element: element || extendElement,
            ref,
        };
        return createElement(Component, elementProps);
    });
    _WrappedComponent.displayName = `TastyWrappedComponent(${getDisplayName(Component, defaultProps.qa ?? extendTag ?? 'Anonymous')})`;
    return _WrappedComponent;
}
function tastyElement(tastyOptions) {
    let { as: originalAs = 'div', element: defaultElement, styles: defaultStyles, styleProps, variants, tokens: defaultTokens, ...defaultProps } = tastyOptions;
    let _TastyComponent;
    if (variants) {
        const variantEntries = Object.entries(variants);
        const variantComponents = variantEntries.reduce((map, [variant, variantStyles]) => {
            map[variant] = tastyElement({
                as: originalAs,
                styles: mergeStyles(defaultStyles, variantStyles),
                styleProps,
                tokens: defaultTokens,
                ...defaultProps,
            });
            return map;
        }, {});
        if (!variantComponents['default']) {
            variantComponents['default'] = tastyElement({
                as: originalAs,
                styles: defaultStyles,
                styleProps,
                tokens: defaultTokens,
                ...defaultProps,
            });
        }
        // eslint-disable-next-line react/display-name
        _TastyComponent = forwardRef((allProps, ref) => {
            const { variant, ...restProps } = allProps;
            const Component = variantComponents[variant || 'default'] ??
                variantComponents['default'];
            const componentProps = restProps;
            const elementProps = {
                ...componentProps,
                ref,
            };
            return createElement(Component, elementProps);
        });
    }
    else {
        let { qa: defaultQa, qaVal: defaultQaVal, ...otherDefaultProps } = defaultProps ?? {};
        // eslint-disable-next-line react/display-name
        _TastyComponent = forwardRef((allProps, ref) => {
            let { as, styles, variant: _omitVariant, mods, element, qa, qaVal, className: userClassName, tokens, style, ...otherProps } = allProps;
            // Optimize propStyles extraction - avoid creating empty objects
            let propStyles = null;
            const propsToCheck = styleProps
                ? styleProps.concat(BASE_STYLES)
                : BASE_STYLES;
            for (const prop of propsToCheck) {
                const key = prop;
                if (!propStyles)
                    propStyles = {};
                if (key in otherProps) {
                    propStyles[key] = otherProps[key];
                    delete otherProps[key];
                }
            }
            if (!styles ||
                (styles && Object.keys(styles).length === 0)) {
                styles = undefined;
            }
            // Merge default styles with instance styles and prop styles
            const allStyles = useMemo(() => {
                const hasStyles = styles && Object.keys(styles).length > 0;
                const hasPropStyles = propStyles && Object.keys(propStyles).length > 0;
                if (!hasStyles && !hasPropStyles) {
                    return defaultStyles;
                }
                return mergeStyles(defaultStyles, styles, propStyles);
            }, [styles, propStyles]);
            // Use the useStyles hook for style generation and injection
            const { className: stylesClassName } = useStyles({ styles: allStyles });
            // Merge default tokens with instance tokens (instance overrides defaults)
            const tokensKey = stringifyTokens(tokens);
            const mergedTokens = useMemo(() => {
                if (!defaultTokens && !tokens)
                    return undefined;
                if (!defaultTokens)
                    return tokens;
                if (!tokens)
                    return defaultTokens;
                return { ...defaultTokens, ...tokens };
            }, [tokensKey]);
            // Process merged tokens into inline style properties
            const processedTokenStyle = useMemo(() => {
                return processTokens(mergedTokens);
            }, [mergedTokens]);
            // Merge processed tokens with explicit style prop (style has priority)
            const mergedStyle = useMemo(() => {
                if (!processedTokenStyle && !style)
                    return undefined;
                if (!processedTokenStyle)
                    return style;
                if (!style)
                    return processedTokenStyle;
                return { ...processedTokenStyle, ...style };
            }, [processedTokenStyle, style]);
            let modProps;
            if (mods) {
                const modsObject = mods;
                modProps = modAttrs(modsObject);
            }
            // Merge user className with generated className
            const finalClassName = [userClassName || '', stylesClassName]
                .filter(Boolean)
                .join(' ');
            const elementProps = {
                'data-element': element || defaultElement,
                'data-qa': qa || defaultQa,
                'data-qaval': qaVal || defaultQaVal,
                ...otherDefaultProps,
                ...(modProps || {}),
                ...otherProps,
                className: finalClassName,
                style: mergedStyle,
                ref,
            };
            // Apply the helper to handle is* properties
            handleIsProperties(elementProps);
            const renderedElement = createElement(as ?? originalAs, elementProps);
            return renderedElement;
        });
    }
    _TastyComponent.displayName = `TastyComponent(${defaultProps.qa || originalAs})`;
    return _TastyComponent;
}
export const Element = tasty({});

        