package handler

import (
	"fmt"
	"strconv"
	"strings"
	"testing"

	"github.com/dailymotion/allure-go"

	"github.com/gavv/httpexpect/v2"
	"github.com/tidbcloud/qa-Gourd/common"
	"github.com/tidbcloud/qa-Gourd/util"
)

func CheckResult(t *testing.T, cs *common.GourdCase) {
	res := cs.Res
	rRes := res.Raw()

	if rRes == nil {
		return
	}
	content := rRes.Header.Get("Content-Type")
	//fmt.Println("content:")
	//fmt.Println(content)
	t2 := strings.Split(content, ";") //text/plain; charset=utf-8

	switch t2[0] {
	case "application/json":
		fmt.Println("resp is:", res.JSON().Raw())
		allure.Step(
			allure.Story(cs.Desc),
			allure.Description(fmt.Sprintf("expect code is:%d, actual code is:%d, resp is:%v, X-Debug-Trace-Id is:%s", cs.Status, cs.Res.Raw().StatusCode, res.JSON().Raw(), res.Header("X-Debug-Trace-Id").Raw())),
			allure.Action(func() {
				res.Status(cs.Status)
			}))

		if len(cs.JsonExpect) != 0 || len(cs.ExpectJsonBoolean) != 0 || len(cs.ExpectJsonInt) != 0 || len(cs.ExpectJsonExist) != 0 {
			tmp := res.JSON().Object()
			p := tmp
			for key, val := range cs.JsonExpect {
				if val == "" {
					continue
				}
				if val == "null" {
					val = ""
				}
				tmp, key = AnalyseKey(key, tmp)
				allure.Step(
					allure.Story(cs.Desc),
					allure.Description(fmt.Sprintf("expect value is:[%s:%s], actual value is:%s", key, val, res.JSON().Path("$."+key).String().Raw())),
					allure.Action(func() {
						if key == "message" {
							fmt.Println("++++++test++++++")
							res.JSON().Path("$." + key).String().Contains(val)
						} else {
							if strings.Contains(res.JSON().Path("$."+key).String().Raw(), "\n") {
								tmp.ContainsKey(key).ValueEqual(key, fmt.Sprintf("%s%s", val, "\n"))
							} else {
								res.JSON().Path("$." + key).String().Equal(val)
								//tmp.ContainsKey(key).ValueEqual(key, val)
							}

						}

					}))
				tmp = p
			}
			for key, val := range cs.ExpectJsonBoolean {
				tmp, key = AnalyseKey(key, tmp)
				allure.Step(
					allure.Story(cs.Desc),
					allure.Description(fmt.Sprintf("expect value is:[%s:%s], actual value is:%v", key, val, res.JSON().Path("$."+key).Raw())),
					allure.Action(func() {
						//tmp.ContainsKey(key).ValueEqual(key, val)
						res.JSON().Path("$." + key).Equal(val)
					}))
				tmp = p
			}
			for key, val := range cs.ExpectJsonInt {
				tmp, key = AnalyseKey(key, tmp)
				allure.Step(
					allure.Story(cs.Desc),
					allure.Description(fmt.Sprintf("expect value is:[%s:%s], actual value is:%v", key, val, res.JSON().Path("$."+key).Raw())),
					allure.Action(func() {
						//tmp.ContainsKey(key).ValueEqual(key, val)
						res.JSON().Path("$." + key).Equal(val)
					}))
				tmp = p
			}
			for key, val := range cs.ExpectJsonExist { //非空则通过测试
				tmp, key = AnalyseKey(key, tmp)
				allure.Step(
					allure.Story(cs.Desc),
					allure.Description(fmt.Sprintf("check the key(%s) is exist?, actual value is:%v", key, res.JSON().Path("$."+key).Raw())),
					allure.Action(func() {
						//tmp.ContainsKey(key).NotEmpty()
						var value *httpexpect.Boolean
						var data string
						switch valuedata := res.JSON().Path("$." + key).Raw().(type) {
						case float64:
							data = strconv.FormatFloat(valuedata, 'E', -1, 64)
						case int:
							data = strconv.Itoa(valuedata)
						case int64:
							data = strconv.FormatInt(valuedata, 10)
						default:
							data = res.JSON().Path("$." + key).Raw().(string)
						}

						if data != "" {
							value = httpexpect.NewBoolean(t, true)
						}
						value.Equal(val)

					}))
			}
		}

	case "text/plain":
		allure.Step(
			allure.Story(cs.Desc),
			allure.Description(fmt.Sprintf("expect code is:%d, actual code is:%d, resp is:%v, X-Debug-Trace-Id is:%s", cs.Status, cs.Res.Raw().StatusCode, res.Body(), res.Header("X-Debug-Trace-Id").Raw())),
			allure.Action(func() {
				res.Status(cs.Status)
			}))

		fmt.Println("resp is:", res.Body())

	case "text/html":
		allure.Step(
			allure.Story(cs.Desc),
			allure.Description(fmt.Sprintf("expect code is:%d, actual code is:%d, resp is:%v, X-Debug-Trace-Id is:%s", cs.Status, cs.Res.Raw().StatusCode, res.Body(), res.Header("X-Debug-Trace-Id").Raw())),
			allure.Action(func() {
				res.Status(cs.Status)
			}))
		fmt.Println("resp is:", res.Body())

	case "application/x-www-form-urlencoded":
		allure.Step(
			allure.Story(cs.Desc),
			allure.Description(fmt.Sprintf("expect code is:%d, actual code is:%d, resp is:%v, X-Debug-Trace-Id is:%s", cs.Status, cs.Res.Raw().StatusCode, res.Body(), res.Header("X-Debug-Trace-Id").Raw())),
			allure.Action(func() {
				res.Status(cs.Status)
			}))
		fmt.Println("resp is:", res.Body())
	}
	fmt.Println("resp is:", res.Header("X-Debug-Trace-Id").Raw())

}

func AnalyseKey(key string, tmp *httpexpect.Object) (*httpexpect.Object, string) {
	var keyChain []string
	keyChain = strings.Split(key, ".")
	keyChainLen := len(keyChain)

	if keyChainLen > 1 {
		switch keyChain[0] {
		//ArrayJson.items.1.xx
		case "ArrayJson":
			var n int
			var err error
			// tmp= tmp.Value(keyChain[1]).Array().Element(n).Object()
			var arrayJson *httpexpect.Array
			arrayJson = tmp.Value(keyChain[1]).Array()
			if keyChain[2] == "last" {
				l := arrayJson.Length().Raw()
				n = int(l) - 1
			} else {
				n, err = strconv.Atoi(keyChain[2])
				util.Check(err)
			}
			tmp = arrayJson.Element(n).Object()
			return tmp, keyChain[3]
		case "Path":
			//Path.aa.bb.cc.dd
			last := keyChainLen - 1
			jsonPath := "$"
			for i := 1; i < last; i++ {
				jsonPath = jsonPath + "." + keyChain[i]
			}
			tmp = tmp.Path(jsonPath).Object()
			return tmp, keyChain[last]

		}
	}
	return tmp, key
}
