package msgdata

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"pbx-api-gin/pkg/utils"
)

// Protocol 定义协议数据结构
type Protocol struct {
	StartBytes    [3]byte // 协议开始符
	SourceID      uint8   // 源设备号
	DestinationID uint8   // 目的设备号
	MessageID     uint8   // 消息号
	DataLength    uint16  // 数据长度
	Data          []byte  // 数据
	Checksum      uint8   // 异或校验码
	EndByte       uint8   // 协议结束符
}

// NewProtocol 创建一个新的 Protocol 实例
func NewProtocol() *Protocol {
	return &Protocol{
		StartBytes: [3]byte{0x7F, 0x8E, 0x9D},
		EndByte:    0xFE,
	}

}

// Encode 将 Protocol 结构体编码为字节切片
func (p *Protocol) Encode() ([]byte, error) {
	// 初始化字节缓冲区
	var buf bytes.Buffer // 写入协议开始符
	buf.Write(p.StartBytes[:])

	//init src and dst ID
	p.SourceID = 0x02
	p.DestinationID = 0x01
	// 写入源设备号、目的设备号和消息号
	binary.Write(&buf, binary.BigEndian, p.SourceID)
	binary.Write(&buf, binary.BigEndian, p.DestinationID)
	binary.Write(&buf, binary.BigEndian, p.MessageID)

	// 写入数据长度
	binary.Write(&buf, binary.BigEndian, p.DataLength)

	// 写入数据
	buf.Write(p.Data[:])

	// 计算校验码
	checksum := p.CalculateChecksum()
	p.Checksum = checksum // 写入校验码
	binary.Write(&buf, binary.BigEndian, p.Checksum)

	// 写入协议结束符
	binary.Write(&buf, binary.BigEndian, p.EndByte)

	return buf.Bytes(), nil
}

// CalculateChecksum 计算校验码
func (p *Protocol) CalculateChecksum() uint8 {
	// 初始化校验码
	checksum := uint8(0)

	// 跳过协议开始符
	data := append([]byte{byte(p.SourceID), byte(p.DestinationID), byte(p.MessageID)},
		append([]byte{byte(p.DataLength >> 8), byte(p.DataLength)}, p.Data...)...)

	// 计算校验码
	for _, b := range data {
		checksum ^= b
	}

	return checksum
}

// Decode 解码字节切片为 Protocol 结构体
func Decode(data []byte) (*Protocol, error) {
	if len(data) < 10 { // 最小长度：3（StartBytes） +1（SourceID） +1（DestinationID） +1（MessageID） +2（DataLength） +1（Checksum） +1（EndByte）
		return nil, fmt.Errorf("data too short")
	}

	p := NewProtocol()

	// 读取协议开始符
	copy(p.StartBytes[:], data[:3])

	// 读取源设备号、目的设备号和消息号
	p.SourceID = data[3]
	p.DestinationID = data[4]
	p.MessageID = data[5]

	// 读取数据长度
	p.DataLength = binary.BigEndian.Uint16(data[6:8])

	// 读取数据
	dataLength := int(p.DataLength)
	if len(data) < 10+dataLength {
		return nil, fmt.Errorf("data length mismatch")
	}
	p.Data = data[8 : 8+dataLength]

	// 读取校验码
	p.Checksum = data[8+dataLength]

	// 读取协议结束符
	p.EndByte = data[9+dataLength]

	// 验证校验码
	if p.Checksum != p.CalculateChecksum() {
		return nil, fmt.Errorf("checksum mismatch")
	}

	return p, nil
}
func SubstrByRune(s string, start, length int) string {
	runes := []rune(s)
	if start >= len(runes) {
		return ""
	}
	end := start + length
	if end > len(runes) {
		end = len(runes)
	}
	return string(runes[start:end])
}

func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
	data := buf.Bytes()
	leng := buf.Len()

	//lfshook.NewLogger().Logger.Infof("========start=========ExtractPacket raw data len=%d, hex=%x", leng, data)

	// Step 1: 查找起始标记 0x7f 0x8e 0x9d
	startIdx := -1
	for i := 0; i <= len(data)-3; i++ { // <= len-3 防止越界
		if data[i] == 0x7f && data[i+1] == 0x8e && data[i+2] == 0x9d {
			startIdx = i
			break
		}
	}

	if startIdx == -1 {
		//无起始标记：保守策略——丢弃过长脏数据，保留最后 MAX_LOOKAHEAD 字节防漏包
		const MAX_LOOKAHEAD = 32
		if leng > MAX_LOOKAHEAD {
			buf.Next(leng - MAX_LOOKAHEAD)
			utils.LoggerDebug.Printf("No start marker found, trimmed buffer to last %d bytes .", MAX_LOOKAHEAD)
		}
		return nil, nil // 明确告知：需继续读取
	}

	// Step 2: 安全读取 DataLength（偏移 startIdx+6 ~ startIdx+8）
	if startIdx+8 > len(data) {
		utils.LoggerDebug.Printf("startIdx=%d, need data[%d:%d] for DataLength but len=%d → insufficient data .",
			startIdx, startIdx+6, startIdx+8, len(data))
		return nil, nil // 数据不够，等下次读取
	}

	dataLen := binary.BigEndian.Uint16(data[startIdx+6 : startIdx+8])
	//lfshook.NewLogger().Logger.Infof("ExtractPacket datalen=%d (0x%04x) at offset %d", dataLen, dataLen, startIdx+6)

	// Step 3: 计算理论包结束位置：startIdx + 8（头长） + dataLen + 1（0xFE）
	endPosTheo := startIdx + 8 + int(dataLen) + 1
	if endPosTheo > len(data) {
		utils.LoggerDebug.Printf("theoretical endPos=%d > data len=%d → need more data .", endPosTheo, len(data))
		return nil, nil // 包未收全，等下次读取
	}
	//lfshook.NewLogger().Logger.Infof("t=================end================%x", data[endPosTheo])
	// Step 4: 在 [startIdx+8+dataLen, endPosTheo] 范围内查找 0xFE（容错：允许在理论位置附近 1~2 字节浮动）
	searchStart := startIdx + 8 + int(dataLen)
	searchEnd := endPosTheo
	if searchEnd > len(data) {
		searchEnd = len(data) // 安全截断
	}

	endIdx := -1
	for i := searchStart; i <= searchEnd; i++ {
		if data[i] == 0xFE {
			endIdx = i
			break
		}
	}

	if endIdx == -1 {
		utils.LoggerDebug.Printf("0xFE not found in expected range [%d,%d), dataLen=%d .", searchStart, searchEnd, dataLen)
		return nil, nil // 结束符缺失，但可能是延迟到达，继续等
	}

	//找到完整包：[startIdx, endIdx]（含两端）
	packetLen := endIdx - startIdx + 1
	packet := make([]byte, packetLen)
	copy(packet, data[startIdx:endIdx+1])

	// 从 buffer 中移除已处理部分
	buf.Next(endIdx + 1)
	//lfshook.NewLogger().Logger.Infof("extracted packet len=%d, start=0x7f8e9d, end=0xFE", packetLen)
	//lfshook.NewLogger().Logger.Infof("=============return============== %x", packet)
	return packet, nil
}
