import HeatmapValue from "./HeatmapValue";

/**
 * 将颜色名称或HEX转换为标准的6位HEX格式
 * @param color 颜色名称或HEX值
 * @returns 6位HEX颜色代码
 */
function colorToHex(color: string): string {
    // 如果是HEX格式直接返回
    if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color)) {
        if (color.length === 4) { // 缩写格式如 #fff
            return `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`;
        }
        return color;
    }

    // 创建临时div元素来获取颜色值 (仅在浏览器环境中有效)
    if (typeof document === 'undefined') {
        // 在非浏览器环境 (如 Node.js) 可能需要其他方式或预定义的颜色映射
        // 这里简化处理，如果不在浏览器环境且不是HEX，则抛错
        throw new Error(`无法在当前环境解析颜色名称: ${color}`);
    }

    const tempDiv = document.createElement('div');
    tempDiv.style.color = color;
    document.body.appendChild(tempDiv);

    // 获取计算后的颜色值
    const computedColor = window.getComputedStyle(tempDiv).color;
    document.body.removeChild(tempDiv);

    // 解析rgb/rgba值
    const rgbMatch = computedColor.match(/^rgb(a?)\((\d+),\s*(\d+),\s*(\d+)(?:,\s*\d+\.?\d*)?\)$/i);
    if (rgbMatch) {
        const r = parseInt(rgbMatch[2]).toString(16).padStart(2, '0');
        const g = parseInt(rgbMatch[3]).toString(16).padStart(2, '0');
        const b = parseInt(rgbMatch[4]).toString(16).padStart(2, '0');
        return `#${r}${g}${b}`.toLowerCase();
    }

    throw new Error(`无法解析颜色: ${color}`);
}

/**
 * 在两个HEX颜色之间插值
 * @param startHex 起始颜色
 * @param endHex 结束颜色
 * @param factor 插值因子 (0-1)
 * @returns 插值后的HEX颜色
 */
function interpolateColor(startHex: string, endHex: string, factor: number): string {
    // 确保 factor 在 0 到 1 之间
    factor = Math.max(0, Math.min(1, factor));

    // 去除#号并解析RGB分量
    const start = startHex.substring(1).match(/.{2}/g)!.map(c => parseInt(c, 16));
    const end = endHex.substring(1).match(/.{2}/g)!.map(c => parseInt(c, 16));

    // 计算插值
    const r = Math.round(start[0] + factor * (end[0] - start[0]));
    const g = Math.round(start[1] + factor * (end[1] - start[1]));
    const b = Math.round(start[2] + factor * (end[2] - start[2]));

    // 返回HEX格式
    return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
}


/**
 * 创建一个将数值映射到离散颜色梯度的函数 (类似 d3.scaleQuantize)
 * @param minValue 数值范围最小值
 * @param maxValue 数值范围最大值
 * @param colors 颜色数组，表示渐变的颜色停靠点 (HEX 或颜色名称)
 * @param numColors 期望的离散颜色数量 ( quantize 标度的值域大小)
 * @returns 一个函数，接收一个数值并返回对应的颜色字符串
 */
function createQuantizeColorScale(
    minValue: number,
    maxValue: number,
    colors: string[], // 颜色数组
    numColors: number // 期望的离散颜色数量
): (value: number) => string {
    // 确保颜色数组至少有两个颜色才能形成渐变，否则使用第一个颜色
    if (colors.length < 2) {
        const singleColorHex = colors.length > 0 ? colorToHex(colors[0]) : '#000000'; // 默认黑色
        // 如果颜色少于2个，或者 numColors 为 1，都只返回一个颜色
        return (value: number): string => singleColorHex;
    }

    // 确保 numColors 是正数
    if (numColors <= 0) {
        numColors = 1;
    }

    // 将所有颜色转换为HEX格式
    const hexColors = colors.map(colorToHex);

    // 生成 numColors 个离散颜色作为 quantize 标度的值域
    const colorRange: string[] = [];
    if (numColors === 1) {
        // 如果只要求一种颜色，使用颜色数组的中间色
        const middleColorIndex = Math.floor((hexColors.length - 1) / 2);
        colorRange.push(hexColors[middleColorIndex]);
    } else {
        // 在提供的颜色之间进行插值，生成 numColors 个颜色
        for (let i = 0; i < numColors; i++) {
            // 计算在整个颜色范围内的比例 (0 到 1)
            const globalFactor = i / (numColors - 1);

            // 计算对应的颜色段
            const colorSegment = globalFactor * (hexColors.length - 1);
            const colorIndex = Math.floor(colorSegment);
            const segmentFactor = colorSegment - colorIndex; // 在当前颜色段内的比例

            // 确保索引不会超出范围
            const startColorIndex = Math.max(0, Math.min(hexColors.length - 2, colorIndex));
            const endColorIndex = startColorIndex + 1;

            const startColor = hexColors[startColorIndex];
            const endColor = hexColors[endColorIndex];

            colorRange.push(interpolateColor(startColor, endColor, segmentFactor));
        }
    }


    // 返回一个颜色比例尺函数
    return (value: number): string => {
        // 处理边界情况
        if (value <= minValue) return colorRange[0];
        if (value >= maxValue) return colorRange[colorRange.length - 1];

        // 如果 min 和 max 相同，所有值都映射到第一个颜色 (或中间色如果 numColors === 1)
        if (minValue === maxValue) {
            return colorRange[0];
        }

        // 计算值在范围内的比例 (0 到 1)
        const proportion = (value - minValue) / (maxValue - minValue);

        // 计算对应的颜色段索引
        const colorIndex = Math.floor(proportion * (colorRange.length - 1));

        // 返回对应的颜色
        // 确保索引不会超出范围
        return colorRange[Math.max(0, Math.min(colorRange.length - 1, colorIndex))];
    };
}


/**
 * Preprocesses input data to extract numeric values, determine color scale,
 * and map each numeric value to a color based on the scale.
 * @param data Input data array (can contain numbers or HeatmapValue objects).
 * @param colors An array of colors defining the gradient stops. At least two colors are recommended.
 * @param colorValues The number of discrete colors in the gradient.
 * @param valueRange Optional: A tuple [minValue, maxValue] to manually specify the value range for color mapping. If not provided, the range is calculated from the data.
 * @returns A 2D array of HeatmapValue objects with colors assigned.
 */
export function preprocessValues(
    data: (number | HeatmapValue)[][],
    colors: string[], // 颜色数组
    colorValues: number, // 期望的离散颜色数量
    valueRange: number[] = [] // 手动指定数值范围，默认为空数组
): HeatmapValue[][] {
    // 确保 colorValues 是正数
    if (colorValues <= 0) {
        colorValues = 1; // 至少为1
    }

    const allNumericValues: number[] = [];
    data.forEach(row => {
        row.forEach(cell => {
            if (typeof cell === "number") {
                allNumericValues.push(cell);
            } else if (cell && typeof cell.value === 'number') { // cell 是一个包含 value 属性的 HeatmapValue 对象
                allNumericValues.push(cell.value);
            }
        });
    });

    let minValue: number;
    let maxValue: number;

    // 根据 valueRange 参数确定数值范围
    if (valueRange && valueRange.length === 2 && typeof valueRange[0] === 'number' && typeof valueRange[1] === 'number') {
        minValue = valueRange[0];
        maxValue = valueRange[1];
    } else {
        minValue = Math.min(...allNumericValues);
        maxValue = Math.max(...allNumericValues);
        // // 如果没有手动指定范围，则从数据中计算
        // if (allNumericValues.length === 0) {
        //      // 如果没有数值数据且没有手动指定范围，则默认范围为 [0, 0]
        //     minValue = 0;
        //     maxValue = 0;
        // } else {

        // }
    }
    console.log('min:',minValue,'max',maxValue);
    

    // 如果没有数值数据，或者手动指定范围后数据都在范围外，则对任何数字应用默认颜色
    // 默认颜色使用颜色数组的第一个颜色 (如果颜色数组不为空)
    if (allNumericValues.length === 0 && !(valueRange && valueRange.length === 2)) {

        const defaultColor = colors.length > 0 ? colorToHex(colors[0]) : '#000000'; // 默认黑色

        return data.map((row, rowIdx) => row.map((cell, colIdx) => {
            if (typeof cell === "number") {
                return {
                    value: cell,
                    rowId: rowIdx,
                    columnId: colIdx,
                    color: defaultColor
                };
            }
            // 如果 cell 不是数字，保持原样 (假设已经是 HeatmapValue 或其他类型)
            return cell as HeatmapValue;
        }));
    }


    // 创建颜色比例尺函数
    const colorScale = createQuantizeColorScale(
        minValue,
        maxValue,
        colors, // 使用颜色数组
        colorValues
    );

    // 映射数据到 HeatmapValue 对象
    const datas = data.map((row, rowIdx) => {
        return row.map((cell, colIdx) => {
            if (typeof cell === "number") {
                return {
                    value: cell,
                    rowId: rowIdx,
                    columnId: colIdx,
                    color: colorScale(cell) // 使用新的颜色比例尺
                };
            } else if (cell && typeof cell.value === 'number') {
                // 如果已经是 HeatmapValue 对象并且有数值 value，则重新计算其颜色
                // 同时保留可能已存在的 rowId 和 columnId
                return {
                    ...cell,
                    rowId: cell.rowId !== undefined ? cell.rowId : rowIdx,
                    columnId: cell.columnId !== undefined ? cell.columnId : colIdx,
                    color: colorScale(cell.value) // 使用新的颜色比例尺
                };
            }
            // 如果 cell 不是数字，也不是包含数字 value 的 HeatmapValue 对象，则原样返回
            return cell as HeatmapValue;
        });
    });
    console.log(`datas ===========>`,datas);
    
    return datas
}

