package hap

import (
	"fmt"
	"strconv"
)

const (
	FormatString = "string"
	FormatBool   = "bool"
	FormatFloat  = "float"
	FormatUInt8  = "uint8"
	FormatUInt16 = "uint16"
	FormatUInt32 = "uint32"
	FormatInt32  = "int32"
	FormatUInt64 = "uint64"
	FormatData   = "data"
	FormatTLV8   = "tlv8"

	UnitPercentage = "percentage"
)

var PR = []string{"pr"}
var PW = []string{"pw"}
var PRPW = []string{"pr", "pw"}
var EVPRPW = []string{"ev", "pr", "pw"}
var EVPR = []string{"ev", "pr"}

type Accessory struct {
	AID      uint8      `json:"aid"` // 150 unique accessories per bridge
	Services []*Service `json:"services"`
}

func (a *Accessory) InitIID() {
	serviceN := map[string]byte{}
	for _, service := range a.Services {
		if len(service.Type) > 3 {
			panic(service.Type)
		}

		n := serviceN[service.Type] + 1
		serviceN[service.Type] = n

		if n > 15 {
			panic(n)
		}

		// ServiceID   = ANSSS000
		s := fmt.Sprintf("%x%x%03s000", a.AID, n, service.Type)
		service.IID, _ = strconv.ParseUint(s, 16, 64)

		for _, character := range service.Characters {
			if len(character.Type) > 3 {
				panic(character.Type)
			}

			// CharacterID = ANSSSCCC
			character.IID, _ = strconv.ParseUint(character.Type, 16, 64)
			character.IID += service.IID
		}
	}
}

func (a *Accessory) GetService(servType string) *Service {
	for _, serv := range a.Services {
		if serv.Type == servType {
			return serv
		}
	}
	return nil
}

func (a *Accessory) GetCharacter(charType string) *Character {
	for _, serv := range a.Services {
		for _, char := range serv.Characters {
			if char.Type == charType {
				return char
			}
		}
	}
	return nil
}

func (a *Accessory) GetCharacterByID(iid uint64) *Character {
	for _, serv := range a.Services {
		for _, char := range serv.Characters {
			if char.IID == iid {
				return char
			}
		}
	}
	return nil
}

type Service struct {
	Desc string `json:"description,omitempty"`

	Type       string       `json:"type"`
	IID        uint64       `json:"iid"`
	Primary    bool         `json:"primary,omitempty"`
	Characters []*Character `json:"characteristics"`
	Linked     []int        `json:"linked,omitempty"`
}

func (s *Service) GetCharacter(charType string) *Character {
	for _, char := range s.Characters {
		if char.Type == charType {
			return char
		}
	}
	return nil
}

func ServiceAccessoryInformation(manuf, model, name, serial, firmware string) *Service {
	return &Service{
		Type: "3E", // AccessoryInformation
		Characters: []*Character{
			{
				Type:   "14",
				Format: FormatBool,
				Perms:  PW,
				//Descr:  "Identify",
			}, {
				Type:   "20",
				Format: FormatString,
				Value:  manuf,
				Perms:  PR,
				//Descr:  "Manufacturer",
				//MaxLen: 64,
			}, {
				Type:   "21",
				Format: FormatString,
				Value:  model,
				Perms:  PR,
				//Descr:  "Model",
				//MaxLen: 64,
			}, {
				Type:   "23",
				Format: FormatString,
				Value:  name,
				Perms:  PR,
				//Descr:  "Name",
				//MaxLen: 64,
			}, {
				Type:   "30",
				Format: FormatString,
				Value:  serial,
				Perms:  PR,
				//Descr:  "Serial Number",
				//MaxLen: 64,
			}, {
				Type:   "52",
				Format: FormatString,
				Value:  firmware,
				Perms:  PR,
				//Descr:  "Firmware Revision",
			},
		},
	}
}

func ServiceHAPProtocolInformation() *Service {
	return &Service{
		Type: "A2", // 'HAPProtocolInformation'
		Characters: []*Character{
			{
				Type:   "37",
				Format: FormatString,
				Value:  "1.1.0",
				Perms:  PR,
				//Descr:  "Version",
				//MaxLen: 64,
			},
		},
	}
}
