package comms

import (
	"bytes"
	"encoding/binary"
	"odoki/constants"
	"odoki/ui/onelead"
	"odoki/utils"
	"time"

	"fyne.io/fyne/v2/widget"
	"tinygo.org/x/bluetooth"
)

var (
	adapter                     = bluetooth.DefaultAdapter
	bluetoothDevice             *bluetooth.Device
	Connected                   bool
	heartRateServiceUUID        = bluetooth.ServiceUUIDHeartRate
	heartRateCharacteristicUUID = bluetooth.CharacteristicUUIDHeartRateMeasurement

	rawDataServiceUUID        = bluetooth.ServiceUUIDAdafruitAddressable
	rawDataCharacteristicUUID = bluetooth.CharacteristicUUIDAdafruitRawTXRX

	ReceivedHeartRate uint8
)

func Init() {
	// Enable BLE interface.
	utils.Must("enable BLE stack", adapter.Enable())
}

func Scan(selectWidget *widget.Select, callback func(*widget.Select, *bluetooth.Adapter, bluetooth.ScanResult)) {
	// Start scanning.
	selectWidget.Options = []string{}
	time.AfterFunc(constants.BluetoothScanTimeout, func() {
		adapter.StopScan()
	})
	err := adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) {
		callback(selectWidget, adapter, device)
	})
	utils.Must("start scan", err)
}

func Connect(connectAddress bluetooth.Address) bool {
	device, err := adapter.Connect(connectAddress, bluetooth.ConnectionParams{})
	if err != nil {
		Connected = false
		return false
	} else {
		bluetoothDevice = device
		Connected = true
		// get services
		println("discovering services/characteristics")
		srvcs, err := device.DiscoverServices([]bluetooth.UUID{heartRateServiceUUID})
		utils.Must("discover services", err)

		if len(srvcs) == 0 {
			panic("could not find heart rate service")
		}

		srvc := srvcs[0]

		println("found service", srvc.UUID().String())

		chars, err := srvc.DiscoverCharacteristics([]bluetooth.UUID{heartRateCharacteristicUUID})
		if err != nil {
			println(err)
		}

		if len(chars) == 0 {
			panic("could not find heart rate characteristic")
		}

		char := chars[0]
		println("found characteristic", char.UUID().String())

		char.EnableNotifications(func(buf []byte) {
			println("got data!")
			ReceivedHeartRate = uint8(buf[1])
			onelead.UpdateHeartrate(uint8(buf[1]))
		})

		// get raw data service
		// get services
		println("discovering services/characteristics")
		srvcs, err = device.DiscoverServices([]bluetooth.UUID{rawDataServiceUUID})
		utils.Must("discover services", err)

		if len(srvcs) == 0 {
			panic("could not find raw data service")
		}

		srvc = srvcs[0]

		println("found service", srvc.UUID().String())

		chars, err = srvc.DiscoverCharacteristics([]bluetooth.UUID{rawDataCharacteristicUUID})
		if err != nil {
			println(err)
		}

		if len(chars) == 0 {
			panic("could not find raw data characteristic")
		}

		char = chars[0]
		println("found characteristic", char.UUID().String())

		char.EnableNotifications(func(buf []byte) {
			println("got data!")
			for i := 0; i < constants.ChannelCount; i++ {
				now := buf[i*4+1 : i*4+5]
				nowBuffer := bytes.NewReader(now)
				var nowVar int32
				binary.Read(nowBuffer, binary.BigEndian, &nowVar)
				println(nowVar)
				onelead.LeadBuffer[i] = append(onelead.LeadBuffer[i], nowVar)
			}
		})

		return true
	}

}
