package color

import (
	"math"
)

// LCH represents a color using lightness, chroma and hue (oklch).
func LCH(lightness Value, chroma Value, hue Value) Color {
	hue *= math.Pi / 180.0
	a := chroma * math.Cos(hue)
	b := chroma * math.Sin(hue)

	r, g, b := labToRGB(lightness, a, b)

	r = gammaCorrection(r)
	g = gammaCorrection(g)
	b = gammaCorrection(b)

	return Color{r, g, b}
}

// LAB to linear sRGB
// Source: https://bottosson.github.io/posts/oklab/
func labToRGB(lightness Value, a Value, b Value) (Value, Value, Value) {
	l := lightness + 0.3963377773761749*a + 0.21580375730991364*b
	m := lightness - 0.10556134581565857*a - 0.0638541728258133*b
	s := lightness - 0.08948418498039246*a - 1.2914855480194092*b

	l = l * l * l
	m = m * m * m
	s = s * s * s

	red := 4.0767416621*l - 3.3077115913*m + 0.2309699292*s
	green := -1.2684380046*l + 2.6097574011*m - 0.3413193965*s
	blue := -0.0041960863*l - 0.7034186147*m + 1.7076147010*s

	return red, green, blue
}

// Gamma correction
// Source: IEC 61966-2-2
func gammaCorrection(x Value) Value {
	if x < 0 {
		return 0
	}

	if x <= 0.0031308 {
		return 12.92 * x
	}

	if x < 1.0 {
		return 1.055*math.Pow(x, 1/2.4) - 0.055
	}

	return 1.0
}