package xugu

import (
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

type xuguValue struct {
	// 布尔值,如果值为 true,表示当前字段的数据类型是大对象数据类型
	islob bool
	//字段名
	paramName []byte
	//paramNameLength [2]byte
	// 字段的实际值
	value []byte
	// 值的长度
	valueLength int
	// 字段的类型
	types fieldType
}

// 判断参数个数
func assertParamCount(query string) int {

	paramCount := strings.Count(query, "?")

	return paramCount
}
func assertParamType(dV driver.Value, values *[]xuguValue) error {
	var dest xuguValue
	switch srcv := dV.(type) {

	case int64:
		buf := make([]byte, 8)
		binary.BigEndian.PutUint64(buf, uint64(srcv))
		dest.value = buf
		dest.valueLength = 8
		dest.islob = false
		dest.types = fieldType_I8

	case float64:
		S := strconv.FormatFloat(srcv, 'f', 15, 64)
		dest.value = []byte(S)
		dest.valueLength = len(S)
		dest.islob = false
		dest.types = fieldType_CHAR

	case bool:
		//S := strconv.FormatBool(srcv)
		var tmp []byte
		if srcv {
			tmp = []byte{1}
		} else {
			tmp = []byte{0}
		}

		dest.value = []byte(tmp)
		dest.valueLength = 1
		dest.islob = false
		dest.types = fieldType_BOOL

	case string:
		dest.value = []byte(srcv)
		dest.valueLength = len(srcv)
		dest.islob = false
		dest.types = fieldType_CHAR
		if dest.valueLength == 0 {
			dest.valueLength = 1
			dest.value = []byte{0}
		}

	case time.Time:
		tm := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
			srcv.Year(), int(srcv.Month()), srcv.Day(),
			srcv.Hour(), srcv.Minute(), srcv.Second())
		dest.value = []byte(tm)
		//	dest.valueLength = strings.Count(tm, "") - 1
		dest.valueLength = len(tm)
		dest.islob = false
		//dest.types = fieldType_TIME
		dest.types = fieldType_CHAR
	case []byte:
		dest.value = srcv
		dest.valueLength = len(srcv)
		dest.islob = true
		dest.types = fieldType_BLOB
		if dest.valueLength == 0 {
			dest.valueLength = 1
			dest.value = []byte{0}
		}

	case nil:
		dest.value = nil
		dest.valueLength = 0
		dest.islob = false
		dest.types = fieldType_NULL

	default:
		return errors.New("unknown data type")
	}

	*values = append(*values, dest)
	return nil
}

func parseMsg(readBuf *buffer, pConn *xuguConn) (*allResult, error) {
	var err error
	aR := allResult{}
	for {
		char := readBuf.peekChar()
		switch char {

		case 'K':
			readBuf.reset()
			return &aR, nil

		case '$':
			readBuf.idx++
			if aR.f, err = parseFormArgDescri(readBuf); err != nil {
				return nil, err
			}
			aR.rt = formArgDescri
			//return &aR, err
		case 'A':
			readBuf.idx++
			if aR.s, err = parseSelectResult(readBuf); err != nil {
				return nil, err
			}
			aR.rt = selectResult
		//	return &aR, err

		case 'I':
			readBuf.idx++
			if aR.i, err = parseInsertResult(readBuf); err != nil {
				return nil, err
			}
			aR.rt = insertResult
			//return &aR, err

		case 'U':
			readBuf.idx++
			if aR.u, err = parseUpdateResult(readBuf); err != nil {
				return nil, err
			}
			aR.rt = updateResult
			//return &aR, err

		case 'D':
			readBuf.idx++
			if aR.d, err = parseDeleteResult(readBuf); err != nil {
				return nil, err
			}
			aR.rt = deleteResult
		//	return &aR, err

		case 'E':
			readBuf.idx++

			if aR.e, err = parseErrInfo(readBuf); err != nil {
				return nil, err
			}
			pConn.errStr = aR.e.ErrStr
			aR.rt = errInfo
			//return &aR, err

		case 'W':
			readBuf.idx++
			if aR.w, err = parseWarnInfo(readBuf); err != nil {
				return nil, err
			}
			aR.rt = warnInfo
			//return &aR, err

		case 'M':
			readBuf.idx++
			if aR.m, err = parseMessage(readBuf); err != nil {
				return nil, err
			}
			aR.rt = message
			//return &aR, err

		default:
			return nil, errors.New("parseMsg: unknown message type")
		}

	}
}
func parseSelectResult(readBuf *buffer) (*SelectResult, error) {
	data := &SelectResult{}

	char := readBuf.peekChar()

	//Field_Num
	fn, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}

	Field_Num := binary.LittleEndian.Uint32(fn)
	data.Field_Num = Field_Num
	data.rowIdx = 0

	//获取字段信息
	for i := 0; i < int(Field_Num); i++ {

		field := FieldDescri{}

		//Field_Name_Len
		Field_Name_Len, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		field.FieldNameLen = int(binary.LittleEndian.Uint32(Field_Name_Len))

		//Field_Name:
		Field_Name, err := readBuf.readNext(field.FieldNameLen, false)
		if err != nil {
			return nil, err
		}
		field.FieldName = string(Field_Name)

		//Field_DType:
		Field_DType, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		field.FieldType = fieldType(binary.LittleEndian.Uint32(Field_DType))

		//Field_Preci_Scale:
		Field_Preci_Scale, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}

		fieldPreciScale := binary.LittleEndian.Uint32(Field_Preci_Scale)
		if int32(fieldPreciScale) <= 0 {
			field.FieldPreciScale = fieldPreciScaleInfo{
				scale:    0,
				accuracy: 0,
			}
		} else {
			field.FieldPreciScale = fieldPreciScaleInfo{
				scale:    uint16(fieldPreciScale >> 16),
				accuracy: uint16(fieldPreciScale & 0xFFFF),
			}
		}

		//Field_Flag:
		Field_Flag, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		field.FieldFlag = binary.LittleEndian.Uint32(Field_Flag)
		data.Fields = append(data.Fields, field)
	}

	data.Values = make([][]FieldValue, data.Field_Num)

	//获取字段的行值,并判断类型
	// 使用 Peek 方法检查下一个字节是否为'R'或'K'

	char = readBuf.peekChar()
	//readBuf.idx++
	if char == 'K' {
		return data, nil
	} else if char == 'R' {
		colIdx := 0
		//typeIdx := 0
		readBuf.idx++
		for {
			col := FieldValue{}
			//获取数据的大小
			Col_len, err := readBuf.readNext(4, true)
			if err != nil {
				return nil, err
			}
			col.Col_len = binary.LittleEndian.Uint32(Col_len)

			//获取数据的值
			col.Col_Data, err = readBuf.readNext(int(col.Col_len), false)
			if err != nil {
				return nil, err
			}

			data.Values[colIdx] = append(data.Values[colIdx], col)
			colIdx++

			char := readBuf.peekChar()

			//既不是R 也不是K 代表该行还有其他字段内容没有读取完成
			if char == 'R' {
				readBuf.idx++
				colIdx = 0
				continue
			} else if char == 'K' {

				return data, nil
				//break
			}

		} //for end

	} else if char == '$' {
		fad, err := parseFormArgDescri(readBuf)
		if err != nil {
			return nil, err
		}

		char := readBuf.peekChar()
		//既不是R 也不是K 代表该行还有其他字段内容没有读取完成
		if char == 'K' {
			data.fad = fad
			return data, nil
			//break
		}

		return nil, errors.New("select to $ 解析失败")
	} else {
		return nil, errors.New("解析失败")
	}

}

func parseInsertResult(readBuf *buffer) (*InsertResult, error) {

	//Rowid_Len
	Rowid_L, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	Rowid_Len := binary.LittleEndian.Uint32(Rowid_L)
	//Rowid_Data
	encoded, err := readBuf.readNext(int(Rowid_Len), false)
	if err != nil {
		return nil, err
	}

	//检测是否结束
	char := readBuf.peekChar()

	if char == 'K' {
		return &InsertResult{
			RowidLen:  Rowid_Len,
			RowidData: encoded,
		}, nil
	}
	return nil, errors.New("parseInsertResult error")
}

func parseUpdateResult(readBuf *buffer) (*UpdateResult, error) {
	updatas, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	updateNum := binary.LittleEndian.Uint32(updatas)

	return &UpdateResult{UpdateNum: updateNum}, nil
}

func parseDeleteResult(readBuf *buffer) (*DeleteResult, error) {
	deletes, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	deleteNum := binary.LittleEndian.Uint32(deletes)

	return &DeleteResult{DeleteNum: deleteNum}, nil
}

func parseProcRet(readBuf *buffer) (*ProcRet, error) {
	retDypes, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	retDType := binary.LittleEndian.Uint32(retDypes)
	retDataLens, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	retDataLen := binary.LittleEndian.Uint32(retDataLens)
	retData, err := readBuf.readNext(int(retDataLen), false)
	if err != nil {
		return nil, err
	}

	return &ProcRet{RetDType: retDType, RetDataLen: retDataLen, RetData: retData}, nil
}

func parseOutParamRet(readBuf *buffer) (*OutParamRet, error) {
	outParamNos, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	outParamNo := binary.LittleEndian.Uint32(outParamNos)

	outParamDTypes, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	outParamDType := binary.LittleEndian.Uint32(outParamDTypes)

	outParamLens, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	outParamLen := binary.LittleEndian.Uint32(outParamLens)

	outParamData, err := readBuf.readNext(int(outParamLen), false)
	if err != nil {
		return nil, err
	}

	return &OutParamRet{
		OutParamNo:    outParamNo,
		OutParamDType: outParamDType,
		OutParamLen:   outParamLen,
		OutParamData:  outParamData,
	}, nil
}

func parseErrInfo(readBuf *buffer) (*ErrInfo, error) {
	errStrLens, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	errStrLen := binary.LittleEndian.Uint32(errStrLens)

	errStr, err := readBuf.readNext(int(errStrLen), false)
	if err != nil {
		return nil, err
	}
	return &ErrInfo{ErrStrLen: errStrLen, ErrStr: errStr}, nil

}

func parseWarnInfo(readBuf *buffer) (*WarnInfo, error) {
	warnStrLens, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	warnStrLen := binary.LittleEndian.Uint32(warnStrLens)

	warnStr, err := readBuf.readNext(int(warnStrLen), false)
	if err != nil {
		return nil, err
	}
	return &WarnInfo{WarnStrLen: warnStrLen, WarnStr: warnStr}, nil
}

func parseMessage(readBuf *buffer) (*Message, error) {
	msgStrLens, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	msgStrLen := binary.LittleEndian.Uint32(msgStrLens)

	msgStr, err := readBuf.readNext(int(msgStrLen), false)
	if err != nil {
		return nil, err
	}

	return &Message{MsgStrLen: msgStrLen, MsgStr: msgStr}, nil
}

func parseFormArgDescri(readBuf *buffer) (*FormArgDescri, error) {
	//	FormArgDescri:   '$' Arg_Num { Arg_Name_Len Arg_Name Arg_No Arg_DType Arg_Preci_Scale }+
	Arg_Nums, err := readBuf.readNext(4, true)
	if err != nil {
		return nil, err
	}
	Arg_Num := binary.LittleEndian.Uint32(Arg_Nums)
	formArgDescri := &FormArgDescri{ArgNum: Arg_Num}
	for i := 0; i < int(Arg_Num); i++ {
		arg := ArgDescri{}
		//Arg_Name_Len
		ArgNameLen, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		arg.ArgNameLen = binary.LittleEndian.Uint32(ArgNameLen)
		//Arg_Name
		arg.ArgName, err = readBuf.readNext(int(arg.ArgNameLen), false)
		if err != nil {
			return nil, err
		}
		//Arg_No
		ArgNo, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		arg.ArgNo = binary.LittleEndian.Uint32(ArgNo)
		//Argg_DType
		ArgDType, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		arg.ArgDType = binary.LittleEndian.Uint32(ArgDType)
		//Arg_Preci_Scale
		ArgPreciScale, err := readBuf.readNext(4, true)
		if err != nil {
			return nil, err
		}
		arg.ArgPreciScale = binary.LittleEndian.Uint32(ArgPreciScale)
		formArgDescri.Args = append(formArgDescri.Args, arg)
	}
	return formArgDescri, nil
}