package led

import (
	"fmt"
	"image/color"
	"machine"
	"time"

	"tinygo.org/x/drivers/ws2812"
)

var ledDevice ws2812.Device

func Init(pin machine.Pin) {
	pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	ledDevice = ws2812.New(pin)
}

type RGB struct {
	R, G, B float64
}

type HSL struct {
	H, S, L float64
}

func hueToRGB(v1, v2, h float64) float64 {
	if h < 0 {
		h += 1
	}
	if h > 1 {
		h -= 1
	}
	switch {
	case 6*h < 1:
		return (v1 + (v2-v1)*6*h)
	case 2*h < 1:
		return v2
	case 3*h < 2:
		return v1 + (v2-v1)*((2.0/3.0)-h)*6
	}
	return v1
}

func (c HSL) ToRGB() RGB {
	h := c.H
	s := c.S
	l := c.L

	if s == 0 {
		// it's gray
		return RGB{l, l, l}
	}

	var v1, v2 float64
	if l < 0.5 {
		v2 = l * (1 + s)
	} else {
		v2 = (l + s) - (s * l)
	}

	v1 = 2*l - v2

	r := hueToRGB(v1, v2, h+(1.0/3.0))
	g := hueToRGB(v1, v2, h)
	b := hueToRGB(v1, v2, h-(1.0/3.0))

	return RGB{r, g, b}
}

func RainbowLED(sleep time.Duration, incr float64, startingHue float64) {
	hue := startingHue
	for true {
		rgb := HSL{hue, 1, 0.5}.ToRGB()
		fmt.Println(uint8(rgb.R*255), uint8(rgb.G*255), uint8(rgb.B*255))
		WriteColor(color.RGBA{uint8(rgb.R * 255), uint8(rgb.G * 255), uint8(rgb.B * 255), 255})
		hue += incr
		if hue >= 1 {
			hue -= 1
		}
		time.Sleep(sleep)
	}
}

func WriteColor(colorToWrite color.RGBA) {
	ledDevice.WriteColors([]color.RGBA{colorToWrite})
}
