// Package request ...
//
// Description : gin ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2023-12-29 15:10
package request

import (
	"strings"
	"sync"

	"git.zhangdeman.cn/zhangdeman/consts"
	"git.zhangdeman.cn/zhangdeman/gin/define"
	"git.zhangdeman.cn/zhangdeman/gin/request/parse_body"
	"git.zhangdeman.cn/zhangdeman/trace"
	"git.zhangdeman.cn/zhangdeman/wrapper/op_ternary"
	"github.com/gin-gonic/gin"
)

var (
	WrapperHandle = &wrapperHandle{}
)

type wrapperHandle struct {
}

// GetHeader 读取header
func (wh *wrapperHandle) GetHeader(ctx *gin.Context, headerKey string, defaultVal string) string {
	if nil == ctx {
		return defaultVal
	}
	val := ctx.GetHeader(headerKey)
	return op_ternary.BaseType[string](len(val) > 0, val, defaultVal)
}

// GetCookie 读取cookie
func (wh *wrapperHandle) GetCookie(ctx *gin.Context, cookieName string, defaultVal string) string {
	if nil == ctx {
		return ""
	}
	val, err := ctx.Cookie(cookieName)
	if nil != err {
		return defaultVal
	}
	return op_ternary.BaseType[string](len(val) > 0, val, defaultVal)
}

// GetUri 获取请求URI
func (wh *wrapperHandle) GetUri(ctx *gin.Context, defaultVal string) string {
	if nil != ctx && nil != ctx.Request && nil != ctx.Request.URL {
		return ctx.Request.URL.Path
	}
	return defaultVal
}

// GetScheme 获取scheme
func (wh *wrapperHandle) GetScheme(ctx *gin.Context, defaultVal string) string {
	if nil != ctx && nil != ctx.Request && nil != ctx.Request.URL {
		return ctx.Request.URL.Scheme
	}
	return defaultVal
}

// ParseQuery 获取query参数
func (wh *wrapperHandle) ParseQuery(ctx *gin.Context) map[string]string {
	query := make(map[string]string)
	if nil != ctx && nil != ctx.Request && nil != ctx.Request.URL {
		for paramName, valueList := range ctx.Request.URL.Query() {
			if len(valueList) == 0 {
				query[paramName] = ""
			} else {
				query[paramName] = valueList[0]
			}
		}
		return query
	}
	return query
}

// GetMethod 获取请求方法
func (wh *wrapperHandle) GetMethod(ctx *gin.Context) string {
	if nil != ctx && nil != ctx.Request {
		return ctx.Request.Method
	}
	return ""
}

// GetContentType 获取请求方式
func (wh *wrapperHandle) GetContentType(ctx *gin.Context, defaultVal string) string {
	if nil == ctx {
		return defaultVal
	}
	contentTypeValue := strings.ToLower(ctx.ContentType())
	return op_ternary.BaseType[string](len(contentTypeValue) > 0, contentTypeValue, defaultVal)
}

// GetDomain 获取请求Domain
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:12 2024/9/19
func (wh *wrapperHandle) GetDomain(ctx *gin.Context) string {
	if nil == ctx {
		return ""
	}
	return ctx.Request.Host
}

// ParseBody 获取请求body
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:25 2024/7/26
func (wh *wrapperHandle) ParseBody(ctx *gin.Context) (map[string]any, error) {
	return parse_body.ExecuteForMap(ctx)
}

// GetResponseBody 获取响应body
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:18 2024/1/2
func (wh *wrapperHandle) GetResponseBody(ctx *gin.Context, key string, defaultVal any) any {
	if nil == ctx {
		return defaultVal
	}
	if val, exist := ctx.Get(key); !exist || nil == val {
		return defaultVal
	} else {
		return val
	}
}

// GetClientIp 获取请求客户端IP
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:31 2024/7/23
func (wh *wrapperHandle) GetClientIp(ctx *gin.Context, defaultVal string) string {
	if nil == ctx {
		return defaultVal
	}
	return ctx.ClientIP()
}

// GetUserAgent 获取user_agent
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:32 2024/7/23
func (wh *wrapperHandle) GetUserAgent(ctx *gin.Context, defaultVal string) string {
	if nil == ctx {
		return defaultVal
	}
	return ctx.Request.UserAgent()
}

// GetCtxData 获取请求上下文数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:35 2024/7/23
func (wh *wrapperHandle) GetCtxData(ctx *gin.Context, key string, defaultVal any) any {
	if nil == ctx {
		return defaultVal
	}
	if val, exist := ctx.Get(key); !exist || nil == val {
		return defaultVal
	} else {
		return val
	}
}

// GetCtxStringData 获取字符串数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:37 2024/7/23
func (wh *wrapperHandle) GetCtxStringData(ctx *gin.Context, key string, defaultVal string) string {
	if nil == ctx {
		return defaultVal
	}
	val := ctx.GetString(key)
	if len(val) == 0 {
		return defaultVal
	}
	return val
}

// GetCtxIntData 获取int数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:39 2024/7/23
func (wh *wrapperHandle) GetCtxIntData(ctx *gin.Context, key string, defaultVal int64) int64 {
	if nil == ctx {
		return defaultVal
	}
	val := wh.GetCtxData(ctx, key, nil)
	if nil == val {
		return defaultVal
	}
	return ctx.GetInt64(key)
}

// ParseHeader 解析header数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:04 2024/9/23
func (wh *wrapperHandle) ParseHeader(ctx *gin.Context) map[string]string {
	headerData := map[string]string{}
	if nil == ctx || nil == ctx.Request {
		return headerData
	}
	for headerName, headerVal := range ctx.Request.Header {
		if len(headerVal) > 0 {
			headerData[headerName] = headerVal[0]
		} else {
			headerData[headerName] = ""
		}
	}
	return headerData
}

// ParseCookie 解析cookie数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:06 2024/9/23
func (wh *wrapperHandle) ParseCookie(ctx *gin.Context) map[string]string {
	cookieData := map[string]string{}
	if nil == ctx || nil == ctx.Request {
		return cookieData
	}
	for _, itemCookie := range ctx.Request.Cookies() {
		cookieData[itemCookie.Name] = itemCookie.Value
	}
	return cookieData
}

// GetLogicAfterResponse ...
func (wh *wrapperHandle) GetLogicAfterResponse(ctx *gin.Context) *define.LogicAfterResponse {
	if nil == ctx || nil == ctx.Request {
		return nil
	}
	l, exist := ctx.Get(consts.GinLogicAfterResponseKey)
	if !exist || nil == l {
		l = &define.LogicAfterResponse{
			SuccessHookFuncList: make([]func(ctx *gin.Context), 0),
			FailureHookFuncList: make([]func(ctx *gin.Context), 0),
			Lock:                &sync.RWMutex{},
		}
		ctx.Set(consts.GinLogicAfterResponseKey, l)
	}
	// 就这么写, key值如果被其他人覆盖成非法值, 此处会直接panic
	return l.(*define.LogicAfterResponse)
}

// GetTraceInstance 获取trace实例
func (wh *wrapperHandle) GetTraceInstance(ctx *gin.Context) *trace.Runtime {
	i, exist := ctx.Get(consts.GinTraceInstanceField)
	if !exist || nil == i {
		i = trace.NewRuntime(wh.GetCtxStringData(ctx, consts.GinTraceIDField, ""), 2)
		ctx.Set(consts.GinTraceInstanceField, i)
	}
	return i.(*trace.Runtime)
}
