import { colord } from 'colord';

import type { HslaColor, HsvaColor, RgbaColor } from '../types';

export const round = (number: number, digits = 0, base = 10 ** digits): number => Math.round(base * number) / base;

export const equalColorObjects = (
  a: RgbaColor | HslaColor | HsvaColor,
  b: RgbaColor | HslaColor | HsvaColor,
): boolean => {
  if (a === b) {
    return true;
  }

  for (const prop in a) {
    if ((a as unknown as Record<string, number>)[prop] !== (b as unknown as Record<string, number>)[prop]) {
      return false;
    }
  }

  return true;
};

export const clamp = (number: number, min = 0, max = 1): number => {
  if (number > max) {
    return max;
  }
  if (number < min) {
    return min;
  }
  return number;
};

export const hsvaToHsla = ({ h, s, v, a }: HsvaColor): HslaColor => {
  const hh = ((200 - s) * v) / 100;

  return {
    h: round(h),
    s: round(hh > 0 && hh < 200 ? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100 : 0),
    l: round(hh / 2),
    a: round(a, 2),
  };
};

export const hsvaToHslString = (hsva: HsvaColor): string => {
  const { h, s, l } = hsvaToHsla(hsva);
  return `hsl(${h}, ${s}%, ${l}%)`;
};

export const hsvaToHslaString = (hsva: HsvaColor): string => {
  const { h, s, l, a } = hsvaToHsla(hsva);
  return `hsla(${h}, ${s}%, ${l}%, ${a})`;
};

export const hsvaToRgba = ({ h, s, v, a }: HsvaColor): RgbaColor => {
  // eslint-disable-next-line no-param-reassign
  h = (h / 360) * 6;
  // eslint-disable-next-line no-param-reassign
  s /= 100;
  // eslint-disable-next-line no-param-reassign
  v /= 100;

  const hh = Math.floor(h);
  const b = v * (1 - s);
  const c = v * (1 - (h - hh) * s);
  const d = v * (1 - (1 - h + hh) * s);
  const moduleKey = hh % 6;

  return {
    r: round([v, c, b, b, d, v][moduleKey] * 255),
    g: round([d, v, v, c, b, b][moduleKey] * 255),
    b: round([b, b, d, v, v, c][moduleKey] * 255),
    a: round(a, 2),
  };
};

export const rgbaToHsva = ({ r, g, b, a }: RgbaColor): HsvaColor => {
  const max = Math.max(r, g, b);
  const delta = max - Math.min(r, g, b);

  // eslint-disable-next-line no-nested-ternary
  const hh = delta
    ? // eslint-disable-next-line no-nested-ternary
      max === r
      ? (g - b) / delta
      : max === g
        ? 2 + (b - r) / delta
        : 4 + (r - g) / delta
    : 0;

  return {
    h: round(60 * (hh < 0 ? hh + 6 : hh)),
    s: round(max ? (delta / max) * 100 : 0),
    v: round((max / 255) * 100),
    a,
  };
};

export const toHex = (color: string, disableAlpha?: boolean) => {
  const resColor = colord(color).toRgb();

  return colord({ ...resColor, a: !disableAlpha ? resColor.a : 1 }).toHex();
};
