package m9z

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

	"tgk-touch/internal/global"
)

// 定义任务指令结构
type TaskInstruction struct {
	Type  uint32 `json:"type"` // 指令类型 (ISA_CMP, ISA_GOTO, etc.)
	Param uint32 `json:"param"`
	Value uint32 `json:"value"` // 指令参数
}

// 定义任务结构
type TaskProgram struct {
	Index        uint8             `json:"index"`        // 任务索引 (0~2)
	Size         uint8             `json:"size"`         // 指令数量
	Instructions []TaskInstruction `json:"instructions"` // 指令列表
}

// StartTaskRead 读取开始任务 (优化指令 CMD=0x13)
func StartTaskRead(deviceId string, idx uint8) (*TaskProgram, error) {
	return taskRead(deviceId, startTask, idx, "读取开始任务")
}

// MiddleTaskRead 读取中间任务 (优化指令 CMD=0x14)
func MiddleTaskRead(deviceId string, idx uint8) (*TaskProgram, error) {
	// 实现与StartTaskRead相同，仅CMD不同
	return taskRead(deviceId, middleTask, idx, "读取中间任务")
}

// StopTaskRead 读取结束任务 (优化指令 CMD=0x15)
func StopTaskRead(deviceId string, idx uint8) (*TaskProgram, error) {
	// 实现与StartTaskRead相同，仅CMD不同
	return taskRead(deviceId, stopTask, idx, "读取结束任务")
}

// 通用任务读取函数
func taskRead(deviceId string, cmd M9zCtrl, idx uint8, detail string) (*TaskProgram, error) {
	readResp, err := ReadCmd(deviceId, cmd, detail, uint(idx))
	if err != nil {
		return nil, err
	}

	data := readResp.Data

	// 解析逻辑与StartTaskRead相同
	if idx < 0 || idx > 2 {
		idx = 0
	}
	task := &TaskProgram{Index: idx}
	if len(data) < 1 {
		return nil, fmt.Errorf("invalid task data length")
	}

	task.Size = data[0]
	task.Instructions = make([]TaskInstruction, 0, task.Size)

	for i := 1; i+3 < len(data) && len(task.Instructions) < int(task.Size); i += 4 {
		instruction := binary.LittleEndian.Uint32(data[i : i+4])
		g.Log().Debugf("% X", instruction)
		insType := uint32(instruction >> 28)
		ins := TaskInstruction{Type: insType}

		// 根据指令类型解析参数
		switch insType {
		case 0x01: // ISA_CMP
			// 参数: 源类型 + 比较值
			ins.Param = (instruction >> 24) & 0x0F
			ins.Value = instruction & 0x0000FFFF
		case 0x02: // ISA_GOTO
			// 参数: 跳转类型 + 跳转地址 + 最大次数 + 索引值
			ins.Param = (instruction >> 24) & 0x0F
			ins.Value = ((instruction >> 16) & 0xFF) | ((instruction >> 8) & 0xFF) | (instruction & 0xFF)
		case 0x03: // ISA_DLY
			// 参数: 延迟单位 + 延迟值
			ins.Param = (instruction >> 24) & 0x0F
			ins.Value = instruction & 0x00FFFFFF
		case 0x04: // ISA_OUTPUT
			// 参数: 输出类型 + 输出值
			ins.Param = (instruction >> 24) & 0x0F
			ins.Value = instruction & 0x00FFFFFF // 输出值

		default:
			// 未知指令类型
			ins.Param = instruction
		}

		task.Instructions = append(task.Instructions, ins)
	}

	return task, nil
}

// StartTaskWrite 写入开始任务 (优化指令 CMD=0x13)
func StartTaskWrite(deviceId string, task *TaskProgram) error {
	return taskWrite(deviceId, startTask, task, "写入开始任务")
}

// MiddleTaskWrite 写入中间任务 (优化指令 CMD=0x14)
func MiddleTaskWrite(deviceId string, task *TaskProgram) error {
	return taskWrite(deviceId, middleTask, task, "写入中间任务")
}

// StopTaskWrite 写入结束任务 (优化指令 CMD=0x15)
func StopTaskWrite(deviceId string, task *TaskProgram) error {
	return taskWrite(deviceId, stopTask, task, "写入结束任务")
}

// 通用任务写入函数
func taskWrite(deviceId string, cmd M9zCtrl, task *TaskProgram, detail string) error {
	if task.Size > 23 {
		return fmt.Errorf("任务数量 %+v 太多，超过了上限，请删除一些后重试}", task.Size)
	}
	// 构造数据缓冲区 (1字节大小 + 每个指令4字节)
	buf := make([]byte, 1+4*len(task.Instructions))
	buf[0] = byte(len(task.Instructions))

	offset := 1
	for _, ins := range task.Instructions {
		// 组合指令 (类型在高4位)
		instruction := ins.Type | ins.Param | ins.Value
		// 写入小端序
		binary.LittleEndian.PutUint32(buf[offset:offset+4], instruction)
		offset += 4
	}
	writeResp, err := WriteCmd(deviceId, M9zCtrl(cmd), buf, detail, task.Index)
	if err != nil {
		return err
	}
	if !writeResp.Success {
		return gerror.New("设置失败")
	}
	// 发送写入命令
	return nil
}
