import { clamp } from "lodash"

export function parse(colorStr: string) {
  let match: RegExpMatchArray | null

  let val = [0, 0, 0, 1]
  let model = "rgb"

  if ((match = colorStr.match(regHexAbbr))) {
    const [, m] = match

    for (let i = 0; i < 3; i++) {
      val[i] = parseInt(m[i] + m[i], 16)
    }
  } else if ((match = colorStr.match(regHex))) {
    const [, m] = match

    for (let i = 0; i < 3; i++) {
      const i2 = i * 2
      val[i] = parseInt(m.slice(i2, i2 + 2), 16)
    }
  } else if ((match = colorStr.match(regRgba))) {
    for (let i = 0; i < 3; i++) {
      val[i] = parseInt(match[i + 1], 0)
    }

    if (match[4]) val[3] = parseFloat(match[4])
  } else if ((match = colorStr.match(regRgbaPer))) {
    for (let i = 0; i < 3; i++) {
      val[i] = Math.round(parseFloat(match[i + 1]) * 2.55)
    }

    if (match[4]) val[3] = parseFloat(match[4])
  } else if ((match = colorStr.match(regHsla))) {
    model = "hsl"
    val = [
      ((parseFloat(match[1]) % 360) + 360) % 360,
      clamp(parseFloat(match[2]), 0, 100),
      clamp(parseFloat(match[3]), 0, 100),
      clamp(parseFloat(match[4]), 0, 1),
    ]
  }

  return { val, model }
}

const regHexAbbr = /^#([a-fA-F0-9]{3})$/
const regHex = /^#([a-fA-F0-9]{6})$/
const regRgba =
  /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/
const regRgbaPer =
  /^rgba?\(\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/
const regHsla =
  /^hsla?\(\s*([+-]?\d*[.]?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/

export const hex = {
  encode(bytes: number[]) {
    const hex: string[] = []

    for (let i = 0, len = bytes.length; i < len; i++) {
      const byte = bytes[i]
      hex.push((byte >>> 4).toString(16))
      hex.push((byte & 0xf).toString(16))
    }

    return hex.join("")
  },

  decode(str: string) {
    const bytes = []

    let len = str.length
    if (len % 2 !== 0) len--

    for (let i = 0; i < len; i += 2) {
      bytes.push(parseInt(str.substr(i, 2), 16))
    }

    return bytes
  },
}
