import { parseToHsl, lighten, readableColor as polishedReadableColor, darken, getContrast, hsl, modularScale, stripUnit, math, getValueAndUnit, transparentize, parseToRgb } from 'polished';
import { tryCatch } from '../utils';
const wcagContrast = {
    // https://www.w3.org/TR/WCAG21/#contrast-minimum
    AA: 4.5,
    AALarge: 3,
    // https://www.w3.org/TR/WCAG21/#contrast-enhanced
    AAA: 7,
    AAALarge: 4.5,
    // https://www.w3.org/TR/WCAG21/#non-text-contrast
    AANonText: 3
};
export const isSolidColor = (background) => {
    const rgb = tryCatch(() => parseToRgb(background));
    return (rgb &&
        (rgb.alpha === undefined ||
            (rgb.alpha !== undefined && rgb.alpha === 1)));
};
export const readableColor = (color, { mode = 'light', level = 'AA' } = {}) => {
    const minContrast = typeof level === 'string' ? wcagContrast[level] : level;
    if (mode === 'light' && getContrast('#fff', color) >= minContrast) {
        return '#fff';
    }
    if (mode === 'dark' && getContrast('#000', color) >= minContrast) {
        return '#000';
    }
    return polishedReadableColor(color);
};
const getBackgroundForegroundColors = (color, delta) => {
    const backgroundLightness = tryCatch(() => parseToHsl(color).lightness, () => 1);
    let background = tryCatch(() => lighten(delta, color));
    let foreground = tryCatch(() => readableColor(lighten(delta, color)));
    if (backgroundLightness > 0.35) {
        background = tryCatch(() => darken(delta, color));
        foreground = tryCatch(() => readableColor(darken(delta, color)));
    }
    return { background, foreground };
};
export const getHoverColors = (color) => {
    return getBackgroundForegroundColors(color, 0.1);
};
export const getActiveColors = (color) => {
    return getBackgroundForegroundColors(color, 0.2);
};
export const readableHue = (color1, color2, { mode = 'both', level = 'AA' } = {}) => {
    // if both the color are not solid, return black as fallback
    if (!isSolidColor(color1) && !isSolidColor(color2)) {
        return '#000000';
    }
    // if one of the color is not solid, return the other color
    if (!isSolidColor(color2)) {
        return color1;
    }
    if (!isSolidColor(color1)) {
        return color2;
    }
    const minContrast = typeof level === 'string' ? wcagContrast[level] : level;
    if (getContrast(color1, color2) >= minContrast)
        return color1;
    const { lightness, ...hueSaturation } = parseToHsl(color1);
    let shouldLighten = true;
    let shouldDarken = true;
    let lightEnough = '';
    let darkEnough = '';
    for (let i = 0; i <= 1; i += 0.01) {
        if (shouldLighten) {
            const lightented = hsl({
                ...hueSaturation,
                lightness: Math.min(lightness + i, 1)
            });
            if (getContrast(lightented, color2) >= minContrast) {
                if (mode !== 'dark')
                    return lightented;
                shouldLighten = false;
                lightEnough = lightented;
            }
            if (lightness + i >= 1)
                shouldLighten = false;
        }
        if (shouldDarken) {
            const darkened = hsl({
                ...hueSaturation,
                lightness: Math.max(lightness - i, 0)
            });
            if (getContrast(darkened, color2) >= minContrast) {
                if (mode !== 'light')
                    return darkened;
                shouldDarken = false;
                darkEnough = darkened;
            }
            if (lightness - i <= 0)
                shouldDarken = false;
        }
        if (!shouldLighten && !shouldDarken)
            break;
    }
    if (lightEnough)
        return lightEnough;
    if (darkEnough)
        return darkEnough;
    return readableColor(color2, { mode, level });
};
export const omitProps = (...props) => ({
    shouldForwardProp: (prop, defaultValidatorFn) => !props.includes(prop) && defaultValidatorFn(prop)
});
const stepsMap = {
    xxs: -2,
    xs: -1,
    s: 0,
    m: 1,
    l: 2,
    xl: 3,
    xxl: 4
};
export const calculateFontSize = (baseFontSize, baseFontScale) => {
    return Object.fromEntries(Object.entries(stepsMap).map(([size, steps]) => {
        const calculation = tryCatch(() => baseFontScale === 'linear'
            ? math(`${baseFontSize} + (${steps} * 0.0625rem)`)
            : modularScale(steps, baseFontSize, baseFontScale), () => baseFontSize);
        if (size === 'xs' && Number.parseFloat(`${stripUnit(calculation)}`) < 0.75) {
            return [size, `max(calc((${baseFontSize} + 12px) / 2), 12px)`];
        }
        return [size, `max(${calculation}, 12px)`];
    }));
};
export const calculateForegroundColor = (background, foregroundColor) => {
    if (foregroundColor !== 'auto') {
        return foregroundColor;
    }
    return isSolidColor(background) ? readableColor(background) : '#000000';
};
export const calculateBackgroundAndContrastColor = (background, foregroundColor) => {
    const isGradientBackground = !isSolidColor(background);
    const computedFgColor = calculateForegroundColor(background, foregroundColor);
    const computedBgColor = isGradientBackground ? readableColor(computedFgColor) : background;
    let contrastColor = darken(0.05, computedBgColor);
    if (getContrast(computedBgColor, contrastColor) === 1) {
        contrastColor = lighten(0.15, computedBgColor);
    }
    if (isGradientBackground) {
        contrastColor = transparentize(0.9, computedFgColor);
    }
    return {
        contrastColor,
        backgroundColor: computedBgColor
    };
};
export const getTranslucentColor = (color) => {
    const fallbackColor = isSolidColor(color) ? color : '#000000';
    const luminance = tryCatch(() => parseToHsl(fallbackColor).lightness, () => 1);
    if (luminance > 0.5) {
        return transparentize(0.5, '#ffffff');
    }
    return transparentize(0.95, '#ffffff');
};
/**
 * Converts a CSS time value to a number in milliseconds.
 *
 * @param time - The CSS time value as a string (e.g: "2s", "500ms") or a number. If undefined, returns 0.
 * @returns The time value in milliseconds.
 *   If the input is a number, it is returned as is.
 *   If the input is a string, it is parsed and converted to milliseconds.
 */
export const getCSSTimeInMilliseconds = (time) => {
    if (time === undefined)
        return 0;
    if (typeof time === 'number')
        return time;
    const [value, unit] = getValueAndUnit(time);
    if (unit === 's')
        return value * 1000;
    if (unit === 'ms')
        return value;
    return 0;
};
//# sourceMappingURL=utils.js.map