package m9z

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

	"io"
	"net/http"
	"os"
	"path/filepath"
	g "tgk-touch/internal/global"
	"time"
)

type FirmwareReadBlock struct {
	Address uint32
	Length  uint16
	Data    []byte
}

// FirmwareRead 读取设备指定地址和长度的固件数据
// 参数:
//   - deviceId: 设备ID
//   - address: 读取起始地址（32位，如0x08000000）
//   - length: 读取数据长度（16位，如512字节）
//
// 返回: 读取到的固件数据及可能的错误
func FirmwareRead(deviceId string, address uint32, length uint16) (*FirmwareReadBlock, error) {
	// 1. 构建读取固件的payload
	// 结构说明: [指令类型(1字节)][操作类型(1字节)][索引(1字节)][数据长度(1字节)][地址(4字节小端)][读取长度(2字节小端)]
	payload := make([]byte, 0, 10)                // 固定10字节payload
	payload = append(payload, byte(firmwareData)) // 指令类型: 0x0E (固件数据相关)
	payload = append(payload, CmdRead)            // 操作类型: 0x01 (读取)
	payload = append(payload, 0x00)               // 索引: 固定0x00

	// 数据长度字段: 后续地址(4字节) + 长度(2字节) = 6字节，故为0x06
	payload = append(payload, 0x06)

	// 地址字段: 32位小端序
	addrBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(addrBytes, address)
	payload = append(payload, addrBytes...)

	// 读取长度字段: 16位小端序
	lenBytes := make([]byte, 2)
	binary.LittleEndian.PutUint16(lenBytes, length)
	payload = append(payload, lenBytes...)

	// 2. 计算校验和
	checksum := calCheckSum(payload)

	// 3. 构建完整帧: [帧头][payload][校验和][帧尾]
	frame := []byte{FrameHeader}       // 帧头: 0xEE
	frame = append(frame, payload...)  // 加入payload
	frame = append(frame, checksum)    // 加入校验和
	frame = append(frame, FrameFooter) // 帧尾: 0xFF

	// 4. 发送命令并获取响应
	respData, err := pushCommand(deviceId, frame, "读取固件数据")
	if err != nil {
		return nil, gerror.Wrapf(err, "设备[%s]读取固件数据失败（地址:0x%X, 长度:%d）", deviceId, address, length)
	}

	// 5. 解析响应帧
	frameResp, err := ParseBlockFrame(respData)
	if err != nil {
		return nil, gerror.Wrapf(err, "设备[%s]解析固件响应失败", deviceId)
	}
	block := &FirmwareReadBlock{}
	block.Address = binary.LittleEndian.Uint32(frameResp.Data[0:4])
	block.Length = BytesToUint16LE(frameResp.Data[4:6])
	block.Data = frameResp.Data[6:]

	// 校验返回数据长度是否匹配请求长度
	if block.Length != uint16(length) {
		return nil, fmt.Errorf("设备[%s]固件数据长度不匹配（期望:%d, 实际:%d）", deviceId, length, len(block.Data))
	}

	return block, nil
}

// 解析接收帧
func ParseBlockFrame(data []byte) (*ReadResponse, error) {
	g.Log().Debugf("ParseFrame:[% X]", data)
	s := ""
	for i, d := range data {
		if i == 0 {

		}
		s += fmt.Sprintf("0x%X,", d)
	}
	//g.Log().Debugf("\n ParseFrame:{%s} ", s)
	// 基本长度检查
	if len(data) < 5 {
		return nil,
			NewReadError("frame too short")
	}

	// 验证帧头帧尾
	if data[0] != FrameHeader || data[len(data)-1] != FrameFooter {
		return nil, NewReadError("invalid frame header or footer")
	}

	// 提取有效载荷和校验和
	payload := data[1 : len(data)-2]
	receivedCS := data[len(data)-2]

	// 计算校验和
	if calCheckSum(payload) != receivedCS {
		return nil, NewReadError("checksum mismatch")
	}

	// 解析指令类型
	if len(payload) < 2 {
		return nil, NewReadError("invalid payload length")
	}

	instruction := payload[0]
	_ = payload[1]

	// 判断是否是响应帧（D7位是否置1）
	_ = (instruction & ResponseFlag) != 0

	return parseReadBlockResponse(payload)

}

// GenerateFirmwareShortID 生成固件的短唯一标识
// 参数：
//
//	firmware - 固件字节数组
//
// 返回：
//
//	短唯一字符串、错误（长度非法时）
func GenerateFirmwareShortID(firmware []byte) (shortID string) {
	length := 8
	// 1. 校验长度合法性
	//if length <= 0 || length > 43 { // Base64URL编码SHA256最大43位，十六进制最大64位
	//	return "", fmt.Errorf("短ID长度需在1~43之间（推荐8~16）")
	//}

	// 2. 计算固件的SHA256哈希（核心：内容变则哈希变）
	firmware = append(firmware, byte(len(firmware)))
	hash := sha256.Sum256(firmware)
	hashBytes := hash[:] // 32字节的哈希值

	// 3. Base64URL编码（无特殊字符，比十六进制更短）
	// Base64URL：去掉+、/，替换为-、_，不补=，适合URL/文件名
	base64URL := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(hashBytes)

	// 4. 截取指定长度（前length位），保证短小且唯一
	shortID = base64URL[:length]

	return shortID
}

// 固件升级起始地址
const FirmwareStartAddr = 0x00000000

// FirmwareUpgrade 设备固件完整升级流程
func FirmwareUpgrade(deviceId string, firmware []byte, startAddr uint32) (uniqueId string, addr uint32, err error) {
	blockSize := 512
	initialOffset := int(startAddr - FirmwareStartAddr)
	addr = startAddr // 起始地址

	uniqueId = GenerateFirmwareShortID(firmware)
	if startAddr == FirmwareStartAddr {
		// 1. 擦除扇区
		g.Log().Debug("开始擦除分区")
		_, err = EraseSector(deviceId)
		if err != nil {
			return uniqueId, addr, fmt.Errorf("擦除扇区阶段失败: %v", err)
		}

	} else {
		/*	//	 不是起始就要判断完整性
			blockData := firmware[initialOffset : initialOffset+blockSize]
			blockHash := sha256.Sum256(blockData)
			frimwareVer := hex.EncodeToString(blockHash[:])
			read, err := FirmwareRead(deviceId, startAddr, uint16(blockSize))
			if err != nil {
				return uniqueId, addr, gerror.Wrapf(err, "验证设备上最新固件包失败")
			}
			deviceHash := sha256.Sum256(read.Data)
			deviceVer := hex.EncodeToString(deviceHash[:])
			if deviceVer != frimwareVer {
				os.WriteFile("./blockData.txt", []byte(fmt.Sprintf("% X", blockData)), 0666)
				os.WriteFile("./readData.txt", []byte(fmt.Sprintf("% X", read.Data)), 0666)
				return uniqueId, addr, gerror.Newf("设备最新不完整，建议擦除分区重试 %s != %s %d %d", frimwareVer, deviceVer, len(blockData), len(read.Data))
			}*/
	}

	// 2. 分块下发固件数据（每块512字节，不足补零）
	totalLen := len(firmware)
	blockCount := 0
	// 3. 计算起始地址对应的固件偏移量（核心：地址→偏移量映射）
	g.Log().Debugf("起始地址0x%X对应固件偏移量: %d字节", startAddr, initialOffset)
	for offset := initialOffset; offset < totalLen; offset += blockSize {
		blockCount++
		// 计算当前块数据
		end := offset + blockSize
		if end > totalLen {
			end = totalLen
		}
		blockData := firmware[offset:end]

		// 补零逻辑：如果块大小不足512字节，自动补零到512字节
		if len(blockData) < blockSize {
			paddingLen := blockSize - len(blockData)
			blockData = append(blockData, make([]byte, paddingLen)...)
		}

		blockLen := uint16(len(blockData)) // 补零后长度应为512（最后一块可能补零后等于blockSize）

		// 计算扩展长度（总长度高8位）和数据长度（低8位）
		totalBlockDataLen := 6 + int(blockLen) // 1(ext) + 4(addr) + 2(len) + dataLen
		extDataLen := byte(totalBlockDataLen >> 8)

		// 下发当前块（带重试机制）
		_, err = FirmwareDataWrite(deviceId, extDataLen, addr, blockLen, blockData)
		/*
			for i := 0; i < 100; i++ {
				_, err = FirmwareDataWrite(deviceId, extDataLen, addr, blockLen, blockData)
				if err == nil {
					break
				} else {
					err = fmt.Errorf("下发固件块（偏移%d）失败: %v", offset, err)
					g.Log().Error(err.Error())
				}
				time.Sleep(3 * time.Second)
			}*/
		if err != nil {
			return uniqueId, addr, err
		}

		// 更新地址（按实际补零后的块长度递增）
		addr += uint32(blockLen)

	}

	// 3. 加锁固件
	_, err = LockFirmware(deviceId)
	if err != nil {
		return uniqueId, addr, fmt.Errorf("固件加锁阶段失败: %v", err)
	}

	// 4. 重启设备完成升级
	if err := Restart(deviceId); err != nil {
		return uniqueId, addr, fmt.Errorf("重启设备失败: %v", err)
	}

	return uniqueId, addr, err
}

// EraseSector 擦除设备扇区
// 指令: CMD=0x0D, IDX=0x00
func EraseSector(deviceId string) (*WriteResponse, error) {
	// 固定数据格式: 04 77 88 99 00（参考示例指令）
	data := []byte{0x04, 0x77, 0x88, 0x99, 0x00}

	// 发送写入命令
	resp, err := WriteCmd(deviceId, eraseSector, data, "擦除扇区", UpdateMarker)
	if err != nil {
		return nil, gerror.Wrapf(err, "设备[%s]擦除扇区失败", deviceId)
	}

	// 验证响应状态
	if !resp.Success {
		return nil, fmt.Errorf("设备[%s]擦除扇区响应失败", deviceId)
	}

	return resp, nil
}

// FirmwareDataWrite 下发固件数据到设备
// 参数:
//   - deviceId: 设备ID
//   - extDataLen: 扩展数据长度（高8位，与dataLen组成16位总长度）
//   - addr: 写入地址（4字节）
//   - writeLen: 写入数据长度（2字节）
//   - fileData: 实际固件数据
func FirmwareDataWrite(deviceId string, extDataLen byte, addr uint32, writeLen uint16, fileData []byte) (*WriteResponse, error) {
	// 1. 校验参数合法性
	totalDataLen := uint16(extDataLen)<<8 | uint16(len(fileData)+6) // 7 = 1(ext) + 4(addr) + 2(writeLen)
	if totalDataLen != uint16(extDataLen)<<8|uint16(len(fileData)+6) {
		return nil, fmt.Errorf("数据长度不匹配，扩展长度0x%02X，实际总长度0x%04X", extDataLen, len(fileData)+7)
	}
	if int(writeLen) != len(fileData) {
		return nil, fmt.Errorf("写入长度与文件数据长度不匹配（%d vs %d）", writeLen, len(fileData))
	}

	// 2. 构造升级数据
	upgradeData := make([]byte, 0, 6+len(fileData))
	upgradeData = append(upgradeData, extDataLen) // 扩展数据长度（1字节）

	// 写入地址（4字节，小端序）
	addrBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(addrBytes, addr)
	upgradeData = append(upgradeData, addrBytes...)

	// 写入长度（2字节，小端序）
	lenBytes := make([]byte, 2)
	binary.LittleEndian.PutUint16(lenBytes, writeLen)

	upgradeData = append(upgradeData, lenBytes...)

	// 固件文件数据
	upgradeData = append(upgradeData, fileData...)

	// 3. 构造命令数据（数据长度字段 + 升级数据）
	dataLen := byte(len(upgradeData) - 1&0xFF) // 数据长度（低8位）
	cmdData := append([]byte{dataLen}, upgradeData...)

	// 4. 发送写入命令
	resp, err := WriteCmd(deviceId, firmwareData, cmdData, "下发固件数据", UpdateMarker)
	if err != nil {
		return nil, gerror.Wrapf(err, "\n设备[%s]下发固件数据失败", deviceId)
	}

	if !resp.Success {
		return nil, fmt.Errorf("设备[%s]固件数据写入响应失败", deviceId)
	}

	return resp, nil
}

// LockFirmware 固件数据下发完成后加锁
// 指令: CMD=0x0F, IDX=0x00
func LockFirmware(deviceId string) (*WriteResponse, error) {
	// 无数据 payload（参考示例指令：数据长度0x00）
	resp, err := WriteCmd(deviceId, lockFirmware, []byte{00}, "固件加锁")
	if err != nil {
		return nil, gerror.Wrapf(err, "设备[%s]固件加锁失败", deviceId)
	}

	if !resp.Success {
		return nil, fmt.Errorf("设备[%s]固件加锁响应失败", deviceId)
	}

	return resp, nil
}

// GetFirmwareFromLocal 从本地文件读取固件
// 参数: localPath 本地固件文件路径（如 "./firmware_v1.2.bin"）
func GetFirmwareFromLocal(localPath string) ([]byte, error) {
	// 校验路径合法性
	if localPath == "" {
		return nil, gerror.New("本地固件路径不能为空")
	}
	absPath, err := filepath.Abs(localPath)
	if err != nil {
		return nil, gerror.Wrapf(err, "读取固件绝对路径失败（%s）", localPath)
	}

	// 检查文件是否存在
	fileInfo, err := os.Stat(absPath)
	if err != nil {
		return nil, gerror.Wrapf(err, "固件文件不存在或无法访问（%s）", absPath)
	}
	if fileInfo.IsDir() {
		return nil, gerror.Newf("路径指向目录，不是固件文件（%s）", absPath)
	}

	// 读取文件内容
	firmwareData, err := os.ReadFile(absPath)
	if err != nil {
		return nil, gerror.Wrapf(err, "读取固件文件失败（%s）", absPath)
	}

	g.Log().Infof("成功从本地读取固件，路径：%s，大小：%d字节", absPath, len(firmwareData))
	return firmwareData, nil
}

// GetFirmwareFromURL 从网络URL下载固件
// 参数: url 固件下载地址（如 "http://example.com/firmware_v1.2.bin"）
func GetFirmwareFromURL(url string) ([]byte, error) {
	// 校验URL合法性
	if url == "" {
		return nil, gerror.New("固件下载URL不能为空")
	}
	if filepath.Ext(url) != ".bin" {
		g.Log().Warnf("固件URL后缀非.bin，可能不是有效固件文件（%s）", url)
	}

	// 发送HTTP GET请求（设置超时时间）
	client := &http.Client{
		Timeout: 30 * time.Second, // 30秒超时
	}
	resp, err := client.Get(url)
	if err != nil {
		return nil, gerror.Wrapf(err, "固件下载请求失败（%s）", url)
	}
	defer resp.Body.Close() // 确保响应体关闭

	// 校验响应状态
	if resp.StatusCode != http.StatusOK {
		return nil, gerror.Newf("固件下载失败，HTTP状态码：%d（%s）", resp.StatusCode, url)
	}

	// 读取响应内容
	firmwareData, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, gerror.Wrapf(err, "读取固件响应内容失败（%s）", url)
	}

	g.Log().Infof("成功从网络下载固件，URL：%s，大小：%d字节", url, len(firmwareData))
	return firmwareData, nil
}
