package m9z

import (
	"encoding/binary"
	"fmt"
	"github.com/gogf/gf/v2/errors/gerror"

	"tgk-touch/internal/global"
)

type DeviceConfig struct {
	Latitude        float64 // 纬度（实际值）
	Longitude       float64 // 经度（实际值）
	TimezoneOffset  float64 // 时区偏移（实际值，单位小时，如 UTC+8 为 8.0）
	SunriseAdjust   int     // 日出偏差调整（分钟）
	SunsetAdjust    int     // 日落偏差调整（分钟）
	ProgrammingMode uint8   // 编程模式 0-2
	RS485Address    uint8   // 485地址 (默认0x01)
}

// todo 和实际有出入
func DeviceConfigRead(deviceId string) (*DeviceConfig, error) {
	cmd, err := ReadCmd(deviceId, deviceConfig, "设备配置读取")
	if err != nil {
		return nil, err
	}
	data := cmd.Data

	// 数据长度校验（至少18字节）
	if len(data) < 18 {
		return nil, fmt.Errorf("invalid config data length: %d", len(data))
	}

	dc := &DeviceConfig{}

	// 1. 解析纬度（Byte0-3，小端序int32）
	latInt := float64(binary.LittleEndian.Uint32(data[0:4]))
	dc.Latitude = float64(latInt) / 1_000_000

	// 2. 解析经度（Byte4-7，小端序int32）
	lngInt := float64(binary.LittleEndian.Uint32(data[4:8]))
	dc.Longitude = float64(lngInt) / 1_000_000

	// 3. 解析时区偏移（Byte8-11，小端序int32）
	tzInt := float64(binary.LittleEndian.Uint32(data[8:12]))
	dc.TimezoneOffset = float64(tzInt) / 1_000_000

	// 4. 日出/日落调整（Byte12-13）
	g.Log().Infof("日出日落偏差2% X", data[12:14])
	dc.SunriseAdjust = int(data[12])
	dc.SunsetAdjust = int(data[13])

	// 5. 编程模式（Byte16）
	dc.ProgrammingMode = data[16]

	// 6. 485地址（Byte17）
	dc.RS485Address = data[17]

	return dc, nil
}

func DeviceConfigWrite(deviceId string, dc *DeviceConfig) error {
	// 构造18字节数据缓冲区
	buf := make([]byte, 18)

	// 1. 编码纬度（扩大1,000,000倍）
	latInt := int32(dc.Latitude * 1_000_000)
	binary.LittleEndian.PutUint32(buf[0:4], uint32(latInt))

	// 2. 编码经度
	lngInt := int32(dc.Longitude * 1_000_000)
	binary.LittleEndian.PutUint32(buf[4:8], uint32(lngInt))

	// 3. 编码时区偏移
	tzInt := int32(dc.TimezoneOffset * 1_000_000)
	binary.LittleEndian.PutUint32(buf[8:12], uint32(tzInt))

	// 4. 日出/日落调整
	buf[12] = byte(dc.SunriseAdjust)
	buf[13] = byte(dc.SunsetAdjust)

	// 5. 备用字段（Byte14-15）填充0
	binary.LittleEndian.PutUint16(buf[14:16], 0)

	// 6. 编程模式
	buf[16] = dc.ProgrammingMode

	// 7. 485地址
	buf[17] = dc.RS485Address

	// 发送写入命令
	writeResp, err := WriteCmd(deviceId, deviceConfig, buf, "设备配置写入")
	if err != nil {
		return err
	}
	if !writeResp.Success {
		return gerror.New("写入失败")
	}
	return nil
}
