import { ResourceName } from '@viamrobotics/sdk';
import twColors from 'tailwindcss/colors';
import { Color } from 'three';
// Step 3: linear sRGB → sRGB
const linearToSrgb = (x) => {
    return x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
};
// Step 4: sRGB → hex
const toHex = (x) => {
    const hex = Math.round(x * 255)
        .toString(16)
        .padStart(2, '0');
    return hex;
};
const oklchToHex = (raw) => {
    const match = raw.match(/oklch\(\s*([\d.]+)%\s+([\d.]+)\s+([\d.]+)\s*\)/);
    if (!match) {
        return raw;
    }
    const l = Number.parseFloat(match[1]) / 100;
    const c = Number.parseFloat(match[2]);
    const h = Number.parseFloat(match[3]);
    // Convert h from degrees to radians
    const hRad = (h * Math.PI) / 180;
    // Step 1: OKLCH → OKLab
    const aa = c * Math.cos(hRad);
    const bb = c * Math.sin(hRad);
    // Step 2: OKLab → linear sRGB
    const l_ = l + 0.3963377774 * aa + 0.2158037573 * bb;
    const m_ = l - 0.1055613458 * aa - 0.0638541728 * bb;
    const s_ = l - 0.0894841775 * aa - 1.291485548 * bb;
    const l_cubed = l_ ** 3;
    const m_cubed = m_ ** 3;
    const s_cubed = s_ ** 3;
    const r_linear = +4.0767416621 * l_cubed - 3.3077115913 * m_cubed + 0.2309699292 * s_cubed;
    const g_linear = -1.2684380046 * l_cubed + 2.6097574011 * m_cubed - 0.3413193965 * s_cubed;
    const b_linear = -0.0041960863 * l_cubed - 0.7034186147 * m_cubed + 1.707614701 * s_cubed;
    const r = Math.max(0, Math.min(1, linearToSrgb(r_linear)));
    const g = Math.max(0, Math.min(1, linearToSrgb(g_linear)));
    const b = Math.max(0, Math.min(1, linearToSrgb(b_linear)));
    return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
};
const original = new Color();
const hsl = { h: 0, s: 0, l: 0 };
/**
 * Darkens a THREE.Color by a given percentage while preserving hue.
 * @param color The original THREE.Color instance.
 * @param percent The percentage to darken (0-100).
 * @returns A new THREE.Color instance with the darkened color.
 */
export const darkenColor = (value, percent) => {
    original.set(value);
    original.getHSL(hsl);
    hsl.l = Math.max(0, hsl.l * (1 - percent / 100));
    return new Color().setHSL(hsl.h, hsl.s, hsl.l);
};
export const resourceNameToColor = (resourceName) => {
    return resourceName
        ? new Color(resourceColors[resourceName.subtype])
        : undefined;
};
const darkness = '600';
export const colors = {
    default: oklchToHex(twColors.red[darkness]),
};
export const resourceColors = {
    arm: oklchToHex(twColors.amber[darkness]),
    camera: oklchToHex(twColors.blue[darkness]),
    base: oklchToHex(twColors.slate[darkness]),
    board: oklchToHex(twColors.emerald[darkness]),
    button: oklchToHex(twColors.gray[darkness]),
    encoder: oklchToHex(twColors.lime[darkness]),
    gantry: oklchToHex(twColors.purple[darkness]),
    gripper: oklchToHex(twColors.cyan[darkness]),
    motor: oklchToHex(twColors.orange[darkness]),
    movement_sensor: oklchToHex(twColors.indigo[darkness]),
    pose_tracker: oklchToHex(twColors.rose[darkness]),
    power_sensor: oklchToHex(twColors.violet[darkness]),
    sensor: oklchToHex(twColors.teal[darkness]),
    servo: oklchToHex(twColors.yellow[darkness]),
    switch: oklchToHex(twColors.stone[darkness]),
    webcam: oklchToHex(twColors.sky[darkness]),
};
export const isColorRepresentation = (color) => {
    if (!color)
        return false;
    if (isColorString(color))
        return true;
    if (isColorHex(color))
        return true;
    if (isColor(color))
        return true;
    return false;
};
export const parseColor = (color, defaultColor = 'black') => {
    if (!isColorRepresentation(color))
        return new Color(defaultColor);
    return new Color(color);
};
export const isRGB = (color) => {
    if (!color ||
        typeof color !== 'object' ||
        !('r' in color) ||
        !('g' in color) ||
        !('b' in color)) {
        return false;
    }
    return typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
};
export const parseRGB = (color, defaultColor = { r: 0, g: 0, b: 0 }) => {
    if (!isRGB(color))
        return new Color().setRGB(defaultColor.r > 1 ? defaultColor.r / 255 : defaultColor.r, defaultColor.g > 1 ? defaultColor.g / 255 : defaultColor.g, defaultColor.b > 1 ? defaultColor.b / 255 : defaultColor.b);
    return new Color().setRGB(color.r > 1 ? color.r / 255 : color.r, color.g > 1 ? color.g / 255 : color.g, color.b > 1 ? color.b / 255 : color.b);
};
export const parseOpacity = (opacity, defaultOpacity = 1) => {
    if (typeof opacity !== 'number') {
        return defaultOpacity;
    }
    return opacity > 1 ? opacity / 100 : opacity;
};
const isColor = (color) => {
    if (!color)
        return false;
    return color instanceof Color;
};
const isColorString = (color) => {
    if (!color)
        return false;
    if (typeof color === 'string') {
        const parsed = new Color(color);
        return parsed.isColor;
    }
    return false;
};
const isColorHex = (color) => {
    if (!color)
        return false;
    if (typeof color === 'number') {
        const parsed = new Color(color);
        return parsed.isColor;
    }
    return false;
};
export const rgbaToHex = (rgba) => {
    if (rgba.length < 3)
        return '#333333';
    const r = rgba[0].toString(16).padStart(2, '0');
    const g = rgba[1].toString(16).padStart(2, '0');
    const b = rgba[2].toString(16).padStart(2, '0');
    return `#${r}${g}${b}`;
};
export const rgbaBytesToFloat32 = (bytes) => {
    const out = new Float32Array(bytes.length);
    for (let i = 0; i < bytes.length; i++) {
        out[i] = bytes[i] / 255;
    }
    return out;
};
