package timecalibration

import (
	"encoding/binary"
	"fmt"
	"primesys_producer/src/logger"
	"primesys_producer/src/protocol/crc"
	"primesys_producer/src/server/frame"
	. "primesys_producer/src/types"
	"primesys_producer/src/utils"
	"time"
)

// Protocol Number 0x1F and 0x8A

type LanguageByte byte

const (
	ChineseLang LanguageByte = 0x01
	EnglishLang LanguageByte = 0x02
)

type TimeCalibrationPacket struct {
	LanguageExtendedByte uint16
	SerialNumber         uint16
}

func DecodeTimeCalibration(fr frame.Frame) (TimeCalibrationPacket, error) {

	body := fr.Body()

	const expectedLen = 13

	if len(body) < expectedLen {
		logger.Error("Expected length error og Time Calibration %d", len(body))
		return TimeCalibrationPacket{}, fmt.Errorf("Bytes not complete of Time Calibration (1F) Packet")
	}

	// body = protocol(1) + datetime(6) + language(2) + serial(2) + crc(2)
	lang := binary.BigEndian.Uint16(body[7:9])
	serial := binary.BigEndian.Uint16(fr.SerialNumber())

	return TimeCalibrationPacket{
		SerialNumber:         serial,
		LanguageExtendedByte: lang,
	}, nil
}

// Building ACK Time Packet 1F
func EncodeTimeCalibrationAck(serial uint16, protocolNumber ProtocolNumber, lang uint16) []byte {
	const requiredLen = 11
	timeStamp := uint32(time.Now().Unix())
	timestampBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(timestampBytes, timeStamp)
	s1 := byte(serial >> 8)
	s2 := byte(serial)
	l1 := byte(lang >> 8)
	l2 := byte(lang)
	// CRC covers everything from packet length up to serial number
	crcInput := []byte{requiredLen, byte(protocolNumber)}
	crcInput = append(crcInput, timestampBytes...)
	crcInput = append(crcInput, l1, l2, s1, s2)
	hi, lo := crc.CRC16X25Bytes(crcInput)
	ack := make([]byte, 0, requiredLen+7)
	ack = append(ack, StartShortByte, StartShortByte, requiredLen, byte(protocolNumber))
	ack = append(ack, timestampBytes...)
	ack = append(ack, l1, l2, s1, s2, hi, lo, StopByte1, StopByte2)
	return ack
}

// Bulinding Ack Time Packet for 8A
func EncodeTimeCalibration4GAck(serialByte []byte, protocolNumber ProtocolNumber) []byte {
	const requiredLen = 11
	serial := binary.BigEndian.Uint16(serialByte)

	s1 := byte(serial >> 8)
	s2 := byte(serial)
	dateTime := utils.DateTimeBytes()
	crcInput := []byte{requiredLen, byte(protocolNumber)}
	crcInput = append(crcInput, dateTime...)
	crcInput = append(crcInput, s1, s2)
	hi, lo := crc.CRC16X25Bytes(crcInput)

	ack := make([]byte, 0)
	ack = append(ack, StartShortByte, StartShortByte, requiredLen, byte(protocolNumber))
	ack = append(ack, dateTime...)
	ack = append(ack, s1, s2, hi, lo, StopByte1, StopByte2)
	return ack
}
