Rgb Hsl Conversion

/**
 * Given a color in RGB format, convert it to HSL format.
 *
 * For more info: https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
 *
 * @param {number[]} colorRgb - One dimensional array of integers (RGB color format).
 * @returns {number[]} - One dimensional array of integers (HSL color format).
 *
 * @example
 * const colorRgb = [24, 98, 118]
 *
 * const result = rgbToHsl(colorRgb)
 *
 * // The function returns the corresponding color in HSL format:
 * // result = [193, 66, 28]
 */

const checkRgbFormat = (colorRgb) => colorRgb.every((c) => c >= 0 && c <= 255)

const rgbToHsl = (colorRgb) => {
  if (!checkRgbFormat(colorRgb)) {
    throw new Error('Input is not a valid RGB color.')
  }

  let colorHsl = colorRgb

  let red = Math.round(colorRgb[0])
  let green = Math.round(colorRgb[1])
  let blue = Math.round(colorRgb[2])

  const limit = 255

  colorHsl[0] = red / limit
  colorHsl[1] = green / limit
  colorHsl[2] = blue / limit

  let minValue = Math.min(...colorHsl)
  let maxValue = Math.max(...colorHsl)

  let channel = 0

  if (maxValue === colorHsl[1]) {
    channel = 1
  } else if (maxValue === colorHsl[2]) {
    channel = 2
  }

  let luminance = (minValue + maxValue) / 2

  let saturation = 0

  if (minValue !== maxValue) {
    if (luminance <= 0.5) {
      saturation = (maxValue - minValue) / (maxValue + minValue)
    } else {
      saturation = (maxValue - minValue) / (2 - maxValue - minValue)
    }
  }

  let hue = 0

  if (saturation !== 0) {
    if (channel === 0) {
      hue = (colorHsl[1] - colorHsl[2]) / (maxValue - minValue)
    } else if (channel === 1) {
      hue = 2 + (colorHsl[2] - colorHsl[0]) / (maxValue - minValue)
    } else {
      hue = 4 + (colorHsl[0] - colorHsl[1]) / (maxValue - minValue)
    }
  }

  hue *= 60

  if (hue < 0) {
    hue += 360
  }

  colorHsl[0] = Math.round(hue)
  colorHsl[1] = Math.round(saturation * 100)
  colorHsl[2] = Math.round(luminance * 100)

  return colorHsl
}

export { rgbToHsl }