package main

import (
	"errors"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
)

const (
	ResSuccess      = 0
	ResInternalErr  = 1
	ResUnauthorized = 2
	ResBadRequest   = 3
)

var resCodeMsg = map[int]string{
	ResSuccess:      "success",
	ResInternalErr:  "internal error",
	ResUnauthorized: "unauthorized",
	ResBadRequest:   "bad request",
}

func Lcfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToLower(v)) + str[i+1:]
	}
	return ""
}

func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

func convertJSON2Camel(jsonStr []byte) []byte {
	var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
	converted := keyMatchRegex.ReplaceAllFunc(
		jsonStr,
		func(match []byte) []byte {
			matchStr := string(match)
			key := matchStr[1 : len(matchStr)-2]
			resKey := Lcfirst(Case2Camel(key))
			return []byte(`"` + resKey + `":`)
		},
	)
	return converted
}

func genBizJWT(data *UserAccessTokenInfoData, appId string, hmacSampleSecret []byte) (*jwt.Token, string, error) {
	var tenMinSeconds int64 = 10 * 60
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"uat":     data.AccessToken,
		"uat_exp": time.Now().Unix() + data.ExpiresIn - tenMinSeconds,
		"rt":      data.RefreshToken,
		"rt_exp":  time.Now().Unix() + data.RefreshExpiresIn - tenMinSeconds,
		"app_id":  appId,
	})
	tokenString, err := token.SignedString(hmacSampleSecret)
	return token, tokenString, err
}

type BizResp struct {
	Code           int         `json:"code"`
	Msg            string      `json:"msg"`
	Data           interface{} `json:"data"`
	RefreshedToken string      `json:"refreshedToken,omitempty"`
}

func genBizResBody(c int, m string, d interface{}, t string) *BizResp {
	r := &BizResp{
		Code:           c,
		Msg:            m,
		Data:           d,
		RefreshedToken: t,
	}
	return r
}

func genCusErrBody(c int, m string) *BizResp {
	return genBizResBody(c, m, nil, "")
}

func genErrBody(c int) *BizResp {
	msg := ""
	if resCodeMsg[c] != "" {
		msg = resCodeMsg[c]
	}
	return genBizResBody(c, msg, nil, "")
}

func genSuccBody(ctx *gin.Context, d interface{}) *BizResp {
	_, exists := ctx.Get("refreshUserInfo")
	jwtToken := ctx.GetString("jwtToken")
	if exists {
		return genBizResBody(ResSuccess, resCodeMsg[ResSuccess], d, jwtToken)
	}
	return genBizResBody(ResSuccess, resCodeMsg[ResSuccess], d, "")
}

func genSuccWithToken(d interface{}, t string) *BizResp {
	return genBizResBody(ResSuccess, resCodeMsg[ResSuccess], d, t)
}

func resBizJSON(c *gin.Context, obj interface{}) {
	c.JSON(http.StatusOK, obj)
}

func handleGeneralLarkApiRes(c *gin.Context, lcode int64, msg string) (isHandled bool) {
	if lcode == 4001 {
		resBizJSON(c, genErrBody(ResUnauthorized))
		return true
	}
	if lcode != 0 {
		resBizJSON(c, genCusErrBody(ResInternalErr, errors.New(strconv.FormatInt(lcode, 10)+": "+msg).Error()))
		return true
	}
	return false
}
