package utils

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
	"github.com/tidbcloud/serverless-service/idl/pbgen/proto/common"
)

type FooReq struct {
	A       int
	BaseReq *common.BaseReq
}

type FooResp struct {
	B        int
	BaseResp *common.BaseResp
}

type (
	BarReq  struct{}
	BarResp struct{}
)

type invalidTp struct {
	BaseReq  *int
	BaseResp *int
}

func TestSetTagIntoReq(t *testing.T) {
	Convey("TestSetTagIntoReq", t, func() {
		req := &FooReq{
			BaseReq: &common.BaseReq{
				Tags: map[string]string{
					"a": "b",
				},
			},
		}

		Convey("normal case", func() {
			SetTagIntoReq(req, "k", "v")
			So(req.BaseReq.Tags, ShouldResemble, map[string]string{
				"a": "b",
				"k": "v",
			})
		})
		Convey("should be ok if Tags is nil", func() {
			req.BaseReq.Tags = nil
			SetTagIntoReq(req, "k", "v")
			So(req.BaseReq.Tags, ShouldResemble, map[string]string{
				"k": "v",
			})
		})
		Convey("should ignore if baseReq is not exist", func() {
			SetTagIntoReq(&BarReq{}, "k", "v")
		})
	})
}

func TestGetTagsFromReq(t *testing.T) {
	Convey("TestGetTagsFromReq", t, func() {
		req := &FooReq{
			BaseReq: &common.BaseReq{
				Tags: map[string]string{
					"a": "b",
				},
			},
		}
		Convey("normal case", func() {
			r1 := GetTagsFromReq(req)
			So(r1, ShouldResemble, map[string]string{
				"a": "b",
			})
		})
		Convey("should return nil if tags is nil", func() {
			req.BaseReq.Tags = nil

			r1 := GetTagsFromReq(req)
			So(r1, ShouldBeNil)
		})
		Convey("should ignore if BaseReq is not exist", func() {
			GetTagsFromReq(&BarReq{})
		})
	})
}

func TestSetCodeMsg(t *testing.T) {
	Convey("TestSetCodeMsg", t, func() {
		resp := &FooResp{
			B: 0,
			BaseResp: &common.BaseResp{
				Tags:    map[string]string{},
				ErrCode: 0,
				ErrMsg:  "",
			},
		}
		Convey("normal case", func() {
			SetCodeMsg(resp, 1, "msg")
			So(resp.BaseResp.ErrCode, ShouldEqual, 1)
			So(resp.BaseResp.ErrMsg, ShouldEqual, "msg")
		})
		Convey("should ignore if BaseReq is not exist", func() {
			SetCodeMsg(&BarReq{}, 1, "v")
		})
	})
}

func TestSetTagIntoResp(t *testing.T) {
	Convey("TestSetTagIntoResp", t, func() {
		resp := &FooResp{
			B: 0,
			BaseResp: &common.BaseResp{
				Tags:    map[string]string{},
				ErrCode: 0,
				ErrMsg:  "",
			},
		}
		Convey("normal case", func() {
			SetTagIntoResp(resp, "k", "v")
			So(resp.BaseResp.Tags, ShouldResemble, map[string]string{
				"k": "v",
			})
		})
		Convey("should ignore if BaseReq is not exist", func() {
			SetTagIntoResp(&BarReq{}, "k", "v")
		})
	})
}

func TestGetBaseReqFromReq(t *testing.T) {
	Convey("TestGetBaseReqFromReq", t, func() {
		req := &FooReq{
			BaseReq: &common.BaseReq{
				Tags: map[string]string{
					"a": "b",
				},
			},
		}

		Convey("should return nil if req is nil", func() {
			r1 := GetBaseReqFromReq(nil)
			So(r1, ShouldBeNil)
		})
		Convey("should auto create BaseReq if BaseReq is nil", func() {
			req.BaseReq = nil

			r1 := GetBaseReqFromReq(req)
			So(r1, ShouldNotBeNil)
		})
		Convey("should return nil if BaseReq is not *base.BaseReq", func() {
			So(GetBaseReqFromReq(&invalidTp{}), ShouldBeNil)
		})
	})
}

func TestGetBaseRespFromResp(t *testing.T) {
	Convey("TestGetBaseRespFromResp", t, func() {
		resp := &FooResp{
			B: 0,
			BaseResp: &common.BaseResp{
				Tags:    map[string]string{},
				ErrCode: 0,
				ErrMsg:  "",
			},
		}

		Convey("should return nil if resp is nil", func() {
			r1 := GetBaseRespFromResp(nil)
			So(r1, ShouldBeNil)
		})
		Convey("should auto create BaseResp if BaseResp is nil", func() {
			resp.BaseResp = nil

			r1 := GetBaseRespFromResp(resp)
			So(r1, ShouldNotBeNil)
		})
		Convey("should return nil if BaseResp is not *base.BaseResp", func() {
			So(GetBaseRespFromResp(&invalidTp{}), ShouldBeNil)
		})
	})
}
