package controllers

import (
	"encoding/json"
	"errors"
	"eta/eta_mini_ht_api/common/component/config"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/contants"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/http"
	"eta/eta_mini_ht_api/common/utils/auth"
	stringUtils "eta/eta_mini_ht_api/common/utils/string"
	"fmt"
	"github.com/beego/beego/v2/server/web"
	"net/url"
	"strings"
)

var (
	htConfig = config.GetConfig(contants.HT).(*config.HTBizConfig)
)

type WrapData struct {
	Msg  string
	Data interface{}
}
type BaseResponse struct {
	Ret     int `description:"返回状态码"`
	Msg     string
	ErrMsg  string
	ErrCode int
	Data    interface{} `json:"data,omitempty"`
	Success bool        `description:"true 执行成功，false 执行失败"`
}

type BaseController struct {
	web.Controller
}

func (b *BaseController) FailResponse(errInfo error, msg string) {

	var retData BaseResponse
	var etaError *exception.EtaError
	if !errors.As(errInfo, &etaError) {
		etaError = exception.New(exception.UnknownError)
	}
	retData = BaseResponse{
		Ret:     200,
		Msg:     msg,
		ErrMsg:  etaError.ErrorMsg,
		ErrCode: etaError.ErrorCode,
		Data:    nil}
	b.Data["json"] = retData
	b.ServeJSON()
}

// JsonResult /*
func (b *BaseController) JsonResult(status int, errCode int, errMsg string, msg string, success bool, data interface{}) {
	retData := BaseResponse{
		Ret:     status,
		Msg:     msg,
		ErrMsg:  errMsg,
		ErrCode: errCode,
		Data:    data,
		Success: success}

	b.Ctx.Output.SetStatus(status)
	//content, err := json.Marshal(retData)
	//if err != nil {
	//	logger.Error("加密失败")
	//} else {
	//	if htConfig.NeedEncode() {
	//		content = auth.DesBase64Encrypt(content, htConfig.GetDesCode())
	//	}
	//}
	//fmt.Printf("%s", content)
	//b.Data["json"] = content
	b.Data["json"] = retData
	b.ServeJSON()
}

func (b *BaseController) GetPostParams(data interface{}) {
	err := json.Unmarshal(b.Ctx.Input.RequestBody, data)
	if err != nil {
		logger.Error("解析请求参数失败:%v", err)
		data = nil
	}
}

// Wrap ControllerWrap 是一个用于封装控制器方法的函数
func Wrap(a *BaseController, fn func() (*WrapData, error)) {
	result, err := fn()
	if err != nil {
		logger.Error("%v", err)
		a.FailResponse(err, result.Msg)
		return
	}
	a.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrOK, "", result.Msg, http.Success, result.Data)
}

func (b *BaseController) InitWrapData(msg string) *WrapData {
	return &WrapData{Msg: msg}
}
func (b *BaseController) SuccessResult(msg string, data interface{}, wrapData *WrapData) {
	wrapData.Msg = msg
	wrapData.Data = data
}
func (b *BaseController) FailedResult(msg string, wrapData *WrapData) {
	wrapData.Msg = msg
}

func (b *BaseController) Prepare() {
	var requestBody string
	uri := b.Ctx.Input.URI()
	method := b.Ctx.Input.Method()
	if method == "GET" {
		requestBody = b.Ctx.Request.RequestURI
	} else {
		requestBody, _ = url.QueryUnescape(string(b.Ctx.Input.RequestBody))
	}
	ip := b.Ctx.Input.IP()
	b.Ctx.Input.URL()
	logger.Info("apiRequest:[uri:%s, requestBody:%s, ip:%s]", uri, requestBody, ip)
}
func (b *BaseController) Finish() {
	runMode := web.BConfig.RunMode
	if b.Data["json"] == nil {
		logger.Warn("apiRequest:[异常提醒:%v 接口:URI:%v;无返回值]", runMode, b.Ctx.Input.URI())
		return
	}
	baseRes := b.Data["json"].(BaseResponse)
	content, err := json.Marshal(baseRes)
	if err != nil {
		logger.Error("apiRequest:[应答json格式化失败:%s]", err)
	}
	if !baseRes.Success {
		logger.Info("apiRequest:[异常提醒:%v接口:URI:%v;ErrMsg:&v;Msg:%v]", b.Ctx.Input.URI(), baseRes.ErrMsg, baseRes.Msg)
	} else {
		if baseRes.Data == nil {
			logger.Warn("apiRequest:[异常提醒:%v 接口:URI:%v;无返回值]", runMode, b.Ctx.Input.URI())
			return
		} else {
			logger.Info("apiRequest:[uri:%s, resData:%s, ip:%s]", b.Ctx.Input.URI(), content)
		}
	}
}

type RequestInfo struct {
	Uri       string `json:"uri"`
	IpAddress string `json:"ip_address"`
	Method    string `json:"method"`
	Params    string `json:"params"`
}

func (b *BaseController) ServeJSON(encoding ...bool) {
	var (
		hasIndent   = false
		hasEncoding = false
	)
	if web.BConfig.RunMode == web.PROD {
		hasIndent = false
	}
	if len(encoding) > 0 && encoding[0] == true {
		hasEncoding = true
	}
	b.JSON(b.Data["json"], hasIndent, hasEncoding)
}

func (b *BaseController) JSON(data interface{}, hasIndent bool, coding bool) error {
	b.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
	//desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
	//c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
	// 设置Cookie为HTTPOnly
	b.Ctx.SetCookie("", "", -1, "/", "", false, true, "")

	var content []byte
	var err error
	if hasIndent {
		content, err = json.MarshalIndent(data, "", "  ")
	} else {
		content, err = json.Marshal(data)
	}
	ip := b.Ctx.Input.IP()
	requestBody, err := url.QueryUnescape(string(b.Ctx.Input.RequestBody))
	if err != nil {
		logger.Info("apiRequest:[err:%s]", err.Error())
	}
	b.logUri(content, requestBody, ip)
	if htConfig.NeedEncode() {
		content = auth.DesBase64Encrypt(content, htConfig.GetDesCode())
		content = []byte(`"` + string(content) + `"`)
	}
	if coding {
		content = []byte(stringUtils.StringsToJSON(string(content)))
	}
	return b.Ctx.Output.Body(content)
}

func (b *BaseController) logUri(respContent []byte, requestBody, ip string) {
	authorization := ""
	method := b.Ctx.Input.Method()
	uri := b.Ctx.Input.URI()
	if method != "HEAD" {
		if method == "POST" || method == "GET" {
			authorization = b.Ctx.Input.Header("authorization")
			if authorization == "" {
				authorization = b.Ctx.Input.Header("Authorization")
			}
			if authorization == "" {
				newAuthorization := b.GetString("authorization")
				if newAuthorization != `` {
					authorization = "authorization=" + newAuthorization
				} else {
					newAuthorization = b.GetString("Authorization")
					authorization = "authorization=" + newAuthorization
				}
			} else {
				if strings.Contains(authorization, ";") {
					authorization = strings.Replace(authorization, ";", "$", 1)
				}
			}
			if authorization == "" {
				strArr := strings.Split(uri, "?")
				for k, v := range strArr {
					fmt.Println(k, v)
				}
				if len(strArr) > 1 {
					authorization = strArr[1]
					authorization = strings.Replace(authorization, "Authorization", "authorization", -1)
					fmt.Println(authorization)
				}
			}
		}
	}
	logger.Info("apiRequest:[uri:%s, authorization:%s, requestBody:%s, responseBody:%s, ip:%s]", b.Ctx.Input.URI(), authorization, requestBody, respContent, ip)
	return
}
