"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getReadableColor = exports.getColorFromRange = exports.getReadableTextColor = exports.cleanColorArray = exports.getInvalidHexColors = exports.isHexCodeColor = void 0;
const tslib_1 = require("tslib");
const colorjs_io_1 = tslib_1.__importDefault(require("colorjs.io"));
const IS_HEX_CODE_COLOR_REGEX = /^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/;
const isHexCodeColor = (color) => IS_HEX_CODE_COLOR_REGEX.test(color);
exports.isHexCodeColor = isHexCodeColor;
/**
 * Validates an array of hex color codes
 * @param colors Array of strings to validate as hex colors
 * @returns Array of invalid colors found, empty if all are valid
 */
const getInvalidHexColors = (colors) => colors.filter((color) => !(0, exports.isHexCodeColor)(color));
exports.getInvalidHexColors = getInvalidHexColors;
/**
 * Processes an array of strings, trimming and filtering out empty values
 * @param colors Array of strings to process
 * @returns Cleaned array of strings
 */
const cleanColorArray = (colors) => colors.map((color) => color.trim()).filter((color) => color.length > 0);
exports.cleanColorArray = cleanColorArray;
/**
 * Returns the best contrasting text color (black or white) for a given background color
 * Uses APCA contrast algorithm for accurate perception-based contrast
 * @param backgroundColor Any valid color string (hex, rgb, rgba, named colors, etc.)
 * @returns 'white' or 'black' depending on which has better contrast
 */
const getReadableTextColor = (backgroundColor) => {
    try {
        const onWhite = Math.abs(colorjs_io_1.default.contrastAPCA('white', backgroundColor));
        const onBlack = Math.abs(colorjs_io_1.default.contrastAPCA('black', backgroundColor));
        return onWhite > onBlack ? 'white' : 'black';
    }
    catch (e) {
        // Not supported color string, default to black
        return 'black';
    }
};
exports.getReadableTextColor = getReadableTextColor;
const getColorInterpolator = (colorRange) => {
    if (!(0, exports.isHexCodeColor)(colorRange.start) || !(0, exports.isHexCodeColor)(colorRange.end)) {
        return undefined;
    }
    return colorjs_io_1.default.range(new colorjs_io_1.default(colorRange.start), new colorjs_io_1.default(colorRange.end), {
        space: 'srgb',
    });
};
/**
 * Interpolates a color from a start/end gradient for a value within a min/max
 * range. Shared by the results table renderer and the Excel export so the
 * exported color-scale fills match what is shown in the UI.
 * @returns A hex color string, or undefined when the range/value is invalid
 */
const getColorFromRange = (value, colorRange, minMaxRange) => {
    const interpolateColor = getColorInterpolator(colorRange);
    if (!interpolateColor)
        return undefined;
    const { min, max } = minMaxRange;
    if (min > max || value < min || value > max) {
        return undefined;
    }
    if (min === max) {
        return interpolateColor(1).toString({ format: 'hex' });
    }
    const percentage = (value - min) / (max - min);
    return interpolateColor(percentage).toString({ format: 'hex' });
};
exports.getColorFromRange = getColorFromRange;
/**
 * Adjusts a color to ensure it has sufficient contrast against a background color
 * Keeps the color as close to the original as possible while meeting WCAG AA standards
 * @param foregroundColor Color to adjust (hex, rgb, rgba, named colors, etc.)
 * @param backgroundColor Background color to contrast against
 * @param targetContrast Target contrast ratio (default: 4.5 for WCAG AA)
 * @returns Adjusted color as hex string, or original if already readable
 */
const getReadableColor = (foregroundColor, backgroundColor, targetContrast = 4.5) => {
    try {
        const fg = new colorjs_io_1.default(foregroundColor);
        const bg = new colorjs_io_1.default(backgroundColor);
        const currentContrast = Math.abs(fg.contrast(bg, 'WCAG21'));
        if (currentContrast >= targetContrast) {
            return foregroundColor;
        }
        const fgLCH = fg.to('lch');
        const originalLightness = fgLCH.l;
        let bestColor = fg;
        let bestDelta = Infinity;
        // Try lightening
        for (let lightness = originalLightness; lightness <= 100; lightness += 5) {
            const testColor = fgLCH.clone();
            testColor.l = lightness;
            const contrast = Math.abs(testColor.contrast(bg, 'WCAG21'));
            if (contrast >= targetContrast) {
                const delta = Math.abs(lightness - originalLightness);
                if (delta < bestDelta) {
                    bestColor = testColor;
                    bestDelta = delta;
                }
                break;
            }
        }
        // Try darkening
        for (let lightness = originalLightness; lightness >= 0; lightness -= 5) {
            const testColor = fgLCH.clone();
            testColor.l = lightness;
            const contrast = Math.abs(testColor.contrast(bg, 'WCAG21'));
            if (contrast >= targetContrast) {
                const delta = Math.abs(lightness - originalLightness);
                if (delta < bestDelta) {
                    bestColor = testColor;
                    bestDelta = delta;
                }
                break;
            }
        }
        return bestColor.to('srgb').toString({ format: 'hex' });
    }
    catch (e) {
        return foregroundColor;
    }
};
exports.getReadableColor = getReadableColor;
//# sourceMappingURL=colors.js.map