package main

import (
	"image"
	"machine"
	"time"

	"image/color"

	draw2 "golang.org/x/image/draw"

	"tinygo.org/x/drivers/amg88xx"
	"tinygo.org/x/drivers/encoders"
	"tinygo.org/x/drivers/st7789"
	"tinygo.org/x/drivers/tone"
	"tinygo.org/x/drivers/ws2812"
)

const AMG88XX_SIZE = 8
const AMG88XX_PIXELS = 24

var data [AMG88XX_SIZE * AMG88XX_SIZE]int16
var pixels [AMG88XX_PIXELS * AMG88XX_PIXELS]int16
var adj [16]int16

func main() {
	time.Sleep(2 * time.Second)
	i2c := machine.I2C1
	i2c.Configure(machine.I2CConfig{
		Frequency: 2.0 * machine.MHz,
		SDA:       machine.P0_17,
		SCL:       machine.P0_20,
	})

	machine.SPI0.Configure(machine.SPIConfig{
		SCK:       machine.P1_01,
		SDO:       machine.P1_02,
		Frequency: 2000000,
		Mode:      0,
	})
	display := st7789.New(machine.SPI0,
		machine.P1_15, // TFT_RESET
		machine.P1_13, // TFT_DC
		machine.P0_10, // TFT_CS
		machine.P0_09) // TFT_LITE

	display.Configure(st7789.Config{
		Rotation:     st7789.ROTATION_90,
		Width:        135,
		Height:       240,
		RowOffset:    40,
		ColumnOffset: 53,
		//FrameRate:  st7789.FRAMERATE_111,
		//VSyncLines: st7789.MAX_VSYNC_SCANLINES,
	})

	width, height := display.Size()
	width = 240
	height = 135
	white := color.RGBA{255, 255, 255, 255}
	red := color.RGBA{255, 0, 0, 255}
	blue := color.RGBA{0, 0, 255, 255}
	green := color.RGBA{0, 255, 0, 255}
	black := color.RGBA{0, 0, 0, 255}

	wsPin := machine.P1_11
	wsPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
	ws := ws2812.NewWS2812(wsPin)
	wsLeds := [2]color.RGBA{}
	for i := range wsLeds {
		wsLeds[i] = black
	}

	machine.InitADC()
	ax := machine.ADC{Pin: machine.P0_29}
	ay := machine.ADC{Pin: machine.P0_02}
	ax.Configure(machine.ADCConfig{})
	ay.Configure(machine.ADCConfig{})

	bzrPin := machine.P0_31
	pwm := machine.PWM0
	speaker, _ := tone.New(pwm, bzrPin)

	enc := encoders.NewQuadratureViaInterrupt(machine.P1_00, machine.P0_24)
	enc.Configure(encoders.QuadratureConfig{
		Precision: 4,
	})

	buttons := []machine.Pin{machine.P0_22, machine.P1_06, machine.P1_04}
	for c := range buttons {
		buttons[c].Configure(machine.PinConfig{Mode: machine.PinInputPullup})
	}

	println("STARTING CAMERA")
	camera := amg88xx.New(machine.I2C1)
	camera.Configure(amg88xx.Config{})
	println("CAMERA STARTED")

	var value int16

	display.FillScreen(black)

	display.FillRectangle(0, 0, width/2, height/2, white)
	display.FillRectangle(width/2, 0, width/2, height/2, red)
	display.FillRectangle(0, height/2, width/2, height/2, green)
	display.FillRectangle(width/2, height/2, width/2, height/2, blue)
	display.FillRectangle(width/4, height/4, width/2, height/2, black)

	redgreen := true
	f := 100
	rotaryOldValue := 0
	for {
		println(ax.Get(), ay.Get())
		if redgreen {
			wsLeds[0] = red
			wsLeds[1] = green
		} else {
			wsLeds[0] = green
			wsLeds[1] = red
		}
		redgreen = !redgreen
		ws.WriteColors(wsLeds[:])
		f++

		if f >= 100 {
			f = 0
			speaker.SetNote(tone.C5)
			time.Sleep(100 * time.Millisecond)
			speaker.Stop()
		}

		if newValue := enc.Position(); newValue != rotaryOldValue {
			println("value: ", newValue)
			rotaryOldValue = newValue
		}
		println("ROTARY BTN:", !buttons[0].Get(), "UP:", !buttons[1].Get(), "DOWN:", !buttons[2].Get())

		// get the values of the sensor in millicelsius
		camera.ReadPixels(&data)

		srcImage := image.NewRGBA(image.Rect(0, 0, 8, 8))
		for j := 0; j < AMG88XX_SIZE; j++ {
			for i := 0; i < AMG88XX_SIZE; i++ {
				value = data[63-(i+j*AMG88XX_SIZE)]
				// treat anything below 18°C as 18°C
				if value < 18000 {
					value = 0
				} else {
					value = (value - 18000) / 36
					// our color array only have 433 values, avoid getting a value that doesn't exist
					if value > 432 {
						value = 432
					}
				}
				srcImage.Set(i, j, colors[value])
			}
		}

		dst := image.NewRGBA(image.Rect(0, 0, 24, 24))
		draw2.BiLinear.Scale(dst, image.Rect(0, 0, 24, 24), srcImage, image.Rect(0, 0, 8, 8), draw2.Over, nil)

		for j := 0; j < AMG88XX_PIXELS; j++ {
			for i := 0; i < AMG88XX_PIXELS; i++ {
				display.FillRectangle(int16(60+(AMG88XX_PIXELS-i-1)*5), 7+int16(j*5), 5, 5, dst.RGBAAt(i, j))
			}
		}

		time.Sleep(100 * time.Millisecond)
	}
}
