package protocol

import (
	"compress/zlib"
	"errors"
	"fmt"
	"github.com/injoyai/base/bytes"
	"github.com/injoyai/base/g"
	"github.com/injoyai/conv"
	"io"
)

const (
	// Prefix 固定帧头
	Prefix = 0x0C

	// PrefixResp 响应帧头
	PrefixResp = 0xB1CB7400
)

type Message interface {
	Bytes() g.Bytes
}

/*
Frame 数据帧
0c 02189300 01 0300 0300 0d00 01
0c 00000000 00 0200 0200 1500
0c 01000000 01 0300 0300 0d00 01
0c 01000000 01 0300 0300 0d00 01
0c 02000000 01 1a00 1a00 3e05 050000000000000002000030303030303101363030303038

0c0100000001030003000d0001
*/
type Frame struct {
	MsgID   uint32  //消息ID
	Control Control //控制码,这个还不知道怎么定义
	Type    uint16  //请求类型,如建立连接，请求分时数据等
	Data    []byte  //数据
}

func (this *Frame) Bytes() g.Bytes {
	length := uint16(len(this.Data) + 2)
	data := make([]byte, 12+len(this.Data))
	data[0] = Prefix
	copy(data[1:], Bytes(this.MsgID))
	data[5] = this.Control.Uint8()
	copy(data[6:], Bytes(length))
	copy(data[8:], Bytes(length))
	copy(data[10:], Bytes(this.Type))
	copy(data[12:], this.Data)
	return data
}

type Response struct {
	Prefix    uint32 //未知,猜测是帧头
	Control   uint8  //响应的控制码,目前发现0c是错误,1c是成功,猜测左数右第4位代表是否成功
	MsgID     uint32 //消息ID
	Unknown   uint8  //未知,猜测是响应的控制码
	Type      uint16 //响应类型,对应请求类型,如建立连接，请求分时数据等
	ZipLength uint16 //数据长度
	Length    uint16 //未压缩长度
	Data      []byte //数据域
}

/*
Decode
帧头		|控制码  	|消息ID    	|控制码   	|数据类型   	|未解压长度  	|解压长度   	|数据域
b1cb7400 	|1c   	|00000000 	|00      	|0d00       |5100      		|bd00     	|789c6378c1cecb252ace6066c5b4898987b9050ed1f90cc5b74c18a5bc18c1b43490fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf70148712002d7f1e13
*/
func Decode(bs []byte) (*Response, error) {
	if len(bs) < 16 {
		return nil, errors.New("数据长度不足")
	}
	resp := &Response{
		Prefix:    Uint32(bs[:4]),
		Control:   bs[4],
		MsgID:     Uint32(bs[5:9]),
		Unknown:   bs[9],
		Type:      Uint16(bs[10:12]),
		ZipLength: Uint16(bs[12:14]),
		Length:    Uint16(bs[14:16]),
		Data:      bs[16:],
	}

	if resp.Control&0x10 != 0x10 {
		//return nil, fmt.Errorf("请求失败,请检查参数")
	}

	if int(resp.ZipLength) != len(bs[16:]) {
		return nil, fmt.Errorf("压缩数据长度不匹配,预期%d,得到%d", resp.ZipLength+16, len(bs))
	}

	//进行数据解压
	if resp.ZipLength != resp.Length {
		r, err := zlib.NewReader(bytes.NewReader(resp.Data))
		if err != nil {
			return nil, err
		}
		defer r.Close()
		resp.Data, err = io.ReadAll(r)
		if err != nil {
			return nil, err
		}
	}

	if int(resp.Length) != len(resp.Data) {
		return nil, fmt.Errorf("解压数据长度不匹配,预期%d,得到%d", resp.Length, len(resp.Data))
	}

	return resp, nil
}

// ReadFrom 这里的r推荐传入*bufio.Reader
func ReadFrom(r io.Reader) (result []byte, err error) {

	prefix := make([]byte, 4)
	for {
		result = []byte(nil)

		//读取帧头
		_, err := io.ReadFull(r, prefix)
		if err != nil {
			return nil, err
		}
		if conv.Uint32(prefix) != PrefixResp {
			continue
		}
		result = append(result, prefix...)

		//读取12字节
		buf := make([]byte, 12)
		_, err = io.ReadFull(r, buf)
		if err != nil {
			return nil, err
		}
		result = append(result, buf...)

		//获取后续字节长度
		length := uint16(result[13])<<8 + uint16(result[12])
		buf = make([]byte, length)
		_, err = io.ReadFull(r, buf)
		if err != nil {
			return nil, err
		}
		result = append(result, buf...)

		return result, nil
	}

}
