package utils

import (
	"encoding/binary"
	"fmt"

	"github.com/AFASystems/presence/internal/pkg/model"
)

// ParseADFast efficiently parses Advertising Data structures
// Returns slice of [startIndex, endIndex] pairs for each AD structure
func ParseADFast(b []byte) [][2]int {
	var res [][2]int
	i := 0

	for i < len(b) {
		l := int(b[i])
		if l == 0 || i+1+l > len(b) {
			break
		}

		res = append(res, [2]int{i, i + 1 + l})

		i += 1 + l
	}

	return res
}

// RemoveFlagBytes removes Bluetooth advertising flag bytes if present
// Some beacons include flag bytes as the first AD structure
func RemoveFlagBytes(b []byte) []byte {
	if len(b) > 1 && b[1] == 0x01 {
		l := int(b[0])
		if 1+l <= len(b) {
			return b[1+l:]
		}
	}
	return b
}

// Generate event based on the Beacon type
func LoopADStructures(b []byte, i [][2]int, id string) model.BeaconEvent {
	be := model.BeaconEvent{}
	for _, r := range i {
		ad := b[r[0]:r[1]]
		if !isValidADStructure(ad) {
			break
		}
		if checkIngics(ad) {
			be = parseIngicsState(ad)
			be.ID = id
			be.Name = id
			break
		} else if checkEddystoneTLM(ad) {
			be = parseEddystoneState(ad)
			be.ID = id
			be.Name = id
			break
		} else if checkMinewB7(ad) {
			fmt.Println("Minew B7 vendor format")
			break
		}
	}

	return be
}

// IsValidADStructure validates if an AD structure is well-formed
func isValidADStructure(data []byte) bool {
	if len(data) < 2 {
		return false
	}

	length := int(data[0])
	return length > 0 && int(length)+1 <= len(data)
}

func checkIngics(ad []byte) bool {
	if len(ad) >= 6 &&
		ad[1] == 0xFF &&
		ad[2] == 0x59 &&
		ad[3] == 0x00 &&
		ad[4] == 0x80 &&
		ad[5] == 0xBC {
		return true
	}

	return false
}

func parseIngicsState(ad []byte) model.BeaconEvent {
	return model.BeaconEvent{
		Battery: uint32(binary.LittleEndian.Uint16(ad[6:8])),
		Event:   int(ad[8]),
		Type:    "Ingics",
	}
}

func checkEddystoneTLM(ad []byte) bool {
	if len(ad) >= 4 &&
		ad[1] == 0x16 &&
		ad[2] == 0xAA &&
		ad[3] == 0xFE &&
		ad[4] == 0x20 {
		return true
	}

	return false
}

func parseEddystoneState(ad []byte) model.BeaconEvent {
	return model.BeaconEvent{
		Battery: uint32(binary.BigEndian.Uint16(ad[6:8])),
		Type:    "Eddystone",
	}
}

// I dont think this is always true, but for testing is ok
func checkMinewB7(ad []byte) bool {
	if len(ad) >= 4 &&
		ad[1] == 0x16 &&
		ad[2] == 0xE1 &&
		ad[3] == 0xFF {
		return true
	}

	return false
}
