package ADL400

import (
	"encoding/binary"
	"fmt"
	"github.com/sigurn/crc16"
)

// readHoldingRegistersBuilder 读取保持寄存器
func ReadHoldingRegistersBuilder(address byte, startAddr, quantity uint16) []byte {
	// 构造Modbus-RTU请求帧
	request := make([]byte, 6)
	request[0] = address                                // 从站地址
	request[1] = 0x03                                   // 功能码：读取保持寄存器
	binary.BigEndian.PutUint16(request[2:4], startAddr) // 起始地址
	binary.BigEndian.PutUint16(request[4:6], quantity)  // 寄存器数量
	// 计算CRC校验
	crcTable := crc16.MakeTable(crc16.CRC16_MODBUS)
	crc := crc16.Checksum(request[:6], crcTable)
	request = append(request, byte(crc&0xFF), byte(crc>>8)) // 添加CRC，低字节在前

	return request
}

// 解析保持寄存器
func ReadHoldingRegisterParse(result []byte, address byte, quantity uint16) ([]uint16, error) {

	// 检查响应最小长度
	if len(result) < 5 {
		return nil, fmt.Errorf("响应长度不足: %d bytes", len(result))
	}

	// 提取数据和CRC
	data := result[:len(result)-2]
	receivedCRC := binary.LittleEndian.Uint16(result[len(result)-2:]) // 解析CRC（小端）

	// 校验CRC
	crcTable := crc16.MakeTable(crc16.CRC16_MODBUS)
	calculatedCRC := crc16.Checksum(data, crcTable)
	if calculatedCRC != receivedCRC {
		return nil, fmt.Errorf("CRC校验失败，计算值: %x，接收值: %x", calculatedCRC, receivedCRC)
	}

	// 验证地址和功能码
	if data[0] != address {
		return nil, fmt.Errorf("响应地址不符，期望: %x，实际: %x", address, data[0])
	}

	switch data[1] {
	case 0x03: // 正常响应
		byteCount := data[2]
		if len(data) < 3+int(byteCount) {
			return nil, fmt.Errorf("响应数据不完整")
		}
		if int(byteCount) != 2*int(quantity) {
			return nil, fmt.Errorf("数据长度不符，期望: %d，实际: %d", 2*quantity, byteCount)
		}

		// 解析寄存器值
		registers := make([]uint16, quantity)
		for i := 0; i < int(quantity); i++ {
			registers[i] = binary.BigEndian.Uint16(data[3+2*i : 5+2*i])
		}
		return registers, nil

	case 0x83: // 异常响应
		if len(data) < 3 {
			return nil, fmt.Errorf("异常响应格式错误")
		}
		return nil, fmt.Errorf("Modbus异常码: %x", data[2])

	default:
		return nil, fmt.Errorf("未知功能码: %x", data[1])
	}
}

// WriteMultipleRegisters 写入多个保持寄存器（功能码0x10）
func WriteMultipleRegistersBuilder(address byte, startAddr uint16, data []uint16) (writeData []byte, quantity uint16) {
	// 构造Modbus-RTU请求帧
	quantity = uint16(len(data))
	byteCount := 2 * quantity

	request := make([]byte, 7+byteCount)
	request[0] = address                                // 从站地址
	request[1] = 0x10                                   // 功能码：写多个寄存器
	binary.BigEndian.PutUint16(request[2:4], startAddr) // 起始地址
	binary.BigEndian.PutUint16(request[4:6], quantity)  // 寄存器数量
	request[6] = byte(byteCount)                        // 字节数

	// 填充数据（大端序）
	for i, value := range data {
		binary.BigEndian.PutUint16(request[7+2*i:9+2*i], value)
	}

	// 计算CRC校验
	crcTable := crc16.MakeTable(crc16.CRC16_MODBUS)
	crc := crc16.Checksum(request[:7+byteCount], crcTable)
	request = append(request, byte(crc&0xFF), byte(crc>>8)) // 添加CRC（低字节在前）

	return request, quantity
}

func WriteMultipleRegistersParse(address byte, startAddr uint16, quantity uint16, response []byte) error {

	// 检查响应最小长度
	if len(response) < 6 {
		return fmt.Errorf("响应长度不足: %d bytes", len(response))
	}

	// 提取数据和CRC
	respData := response[:len(response)-2]
	receivedCRC := binary.LittleEndian.Uint16(response[len(response)-2:])

	// 校验CRC
	crcTable := crc16.MakeTable(crc16.CRC16_MODBUS)
	calculatedCRC := crc16.Checksum(respData, crcTable)
	if calculatedCRC != receivedCRC {
		return fmt.Errorf("CRC校验失败，计算值: %x，接收值: %x", calculatedCRC, receivedCRC)
	}

	// 验证地址和功能码
	if respData[0] != address {
		return fmt.Errorf("响应地址不符，期望: %x，实际: %x", address, respData[0])
	}

	// 处理正常/异常响应
	switch respData[1] {
	case 0x10:
		// 验证写入的地址和数量
		respStart := binary.BigEndian.Uint16(respData[2:4])
		respQuantity := binary.BigEndian.Uint16(respData[4:6])
		if respStart != startAddr || respQuantity != quantity {
			return fmt.Errorf("响应参数不匹配，地址期望: %x 实际: %x，数量期望: %d 实际: %d",
				startAddr, respStart, quantity, respQuantity)
		}
		//log.Print("Modbus:写入成功")
		return nil // 写入成功
	case 0x90: // 异常响应
		if len(respData) < 3 {
			return fmt.Errorf("异常响应格式错误")
		}
		return fmt.Errorf("Modbus异常码: %x", respData[2])
	default:
		return fmt.Errorf("未知功能码: %x", respData[1])
	}
}
