const clamp = (value, min, max) => Math.min(max, Math.max(min, value));

const hueToRgb = (p, q, t) => {
  let temp = t;
  if (temp < 0) temp += 1;
  if (temp > 1) temp -= 1;
  if (temp < 1 / 6) return p + (q - p) * 6 * temp;
  if (temp < 1 / 2) return q;
  if (temp < 2 / 3) return p + (q - p) * (2 / 3 - temp) * 6;
  return p;
};

const hslToRgb = (h, s, l) => {
  const hue = (((h % 360) + 360) % 360) / 360;
  const saturation = clamp(s, 0, 100) / 100;
  const lightness = clamp(l, 0, 100) / 100;

  if (saturation === 0) {
    const gray = Math.round(lightness * 255);
    return { r: gray, g: gray, b: gray };
  }

  const q =
    lightness < 0.5
      ? lightness * (1 + saturation)
      : lightness + saturation - lightness * saturation;
  const p = 2 * lightness - q;

  return {
    r: Math.round(hueToRgb(p, q, hue + 1 / 3) * 255),
    g: Math.round(hueToRgb(p, q, hue) * 255),
    b: Math.round(hueToRgb(p, q, hue - 1 / 3) * 255),
  };
};

const parseColor = (color) => {
  const value = (color || "").trim();

  if (value.startsWith("#")) {
    const normalized = value.replace("#", "");

    if (normalized.length === 3 || normalized.length === 4) {
      const full = normalized
        .split("")
        .map((item) => item + item)
        .join("");
      const hasAlpha = normalized.length === 4;
      return {
        r: Number.parseInt(full.slice(0, 2), 16),
        g: Number.parseInt(full.slice(2, 4), 16),
        b: Number.parseInt(full.slice(4, 6), 16),
        a: hasAlpha ? Number.parseInt(full.slice(6, 8), 16) / 255 : 1,
      };
    }

    if (normalized.length === 6 || normalized.length === 8) {
      const hasAlpha = normalized.length === 8;
      return {
        r: Number.parseInt(normalized.slice(0, 2), 16),
        g: Number.parseInt(normalized.slice(2, 4), 16),
        b: Number.parseInt(normalized.slice(4, 6), 16),
        a: hasAlpha ? Number.parseInt(normalized.slice(6, 8), 16) / 255 : 1,
      };
    }
  }

  const rgbaMatch = value.match(/rgba?\(([^)]+)\)/i);
  if (rgbaMatch) {
    const [r = 0, g = 0, b = 0, a = 1] = rgbaMatch[1]
      .split(",")
      .map((item) => item.trim());
    return {
      r: clamp(Number.parseFloat(r), 0, 255),
      g: clamp(Number.parseFloat(g), 0, 255),
      b: clamp(Number.parseFloat(b), 0, 255),
      a: clamp(Number.parseFloat(a), 0, 1),
    };
  }

  const hslaMatch = value.match(/hsla?\(([^)]+)\)/i);
  if (hslaMatch) {
    const [h = 0, s = 0, l = 0, a = 1] = hslaMatch[1]
      .split(",")
      .map((item) => item.trim().replace("%", ""));
    const rgb = hslToRgb(
      Number.parseFloat(h),
      Number.parseFloat(s),
      Number.parseFloat(l),
    );
    return {
      ...rgb,
      a: clamp(Number.parseFloat(a), 0, 1),
    };
  }

  return { r: 23, g: 100, b: 255, a: 1 };
};

const colorToCss = ({ r, g, b, a = 1 }) => {
  const alpha = clamp(a, 0, 1);
  if (alpha < 1) {
    return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(alpha.toFixed(3))})`;
  }

  const toHex = (value) =>
    clamp(Math.round(value), 0, 255).toString(16).padStart(2, "0");
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
};

const mixColor = (color, target, amount) => {
  const sourceRgb = parseColor(color);
  const targetRgb = parseColor(target);
  return colorToCss({
    r: sourceRgb.r + (targetRgb.r - sourceRgb.r) * amount,
    g: sourceRgb.g + (targetRgb.g - sourceRgb.g) * amount,
    b: sourceRgb.b + (targetRgb.b - sourceRgb.b) * amount,
    a: sourceRgb.a,
  });
};

const colorToRgba = (color, alpha) => {
  const { r, g, b, a } = parseColor(color);
  const nextAlpha = clamp(a * alpha, 0, 1);
  return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(nextAlpha.toFixed(3))})`;
};

export const buildCustomThemeVars = (brandColor) => ({
  "--brand-color": brandColor,
  "--brand-color-hover": mixColor(brandColor, "#FFFFFF", 0.12),
  "--brand-color-active": mixColor(brandColor, "#000000", 0.14),
  "--brand-color-disabled": colorToRgba(brandColor, 0.4),
  "--brand-color-focus": colorToRgba(brandColor, 0.18),
  "--brand-color-light": colorToRgba(brandColor, 0.12),
  "--text-color-brand": brandColor,
  "--text-color-link": brandColor,
  "--el-color-primary": brandColor,
  "--el-color-primary-light-3": mixColor(brandColor, "#FFFFFF", 0.12),
  "--el-color-primary-light-5": mixColor(brandColor, "#FFFFFF", 0.28),
  "--el-color-primary-light-7": mixColor(brandColor, "#FFFFFF", 0.48),
  "--el-color-primary-light-8": mixColor(brandColor, "#FFFFFF", 0.64),
  "--el-color-primary-light-9": mixColor(brandColor, "#FFFFFF", 0.82),
  "--el-color-primary-dark-2": mixColor(brandColor, "#000000", 0.14),
  "--el-menu-hover-bg-color": colorToRgba(brandColor, 0.12),
  "--el-menu-active-color": brandColor,
  "--el-menu-active-background": colorToRgba(brandColor, 0.12),
  "--el-text-color-secondary": brandColor,
});
