package middleware

import (
	"net"
	"slices"
	"time"

	"github.com/duke-git/lancet/v2/netutil"
	"github.com/gogf/gf/v2/encoding/gjson"

	"kami/internal/errHandler"
	"kami/internal/service"

	"github.com/gogf/gf/v2/container/gset"
	"github.com/gogf/gf/v2/errors/gcode"

	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/text/gstr"

	"kami/utility/token"
	"kami/utility/verify"
)

// whiteListAuth 白名单中间件
func whiteListAuth(r *ghttp.Request) gcode.Code {
	whiteList := []string{
		"/api/merchant/order/query",
		"/api/merchant/order/summary",
		"/api/restriction/block/order",
		"/api/restriction/location/checkIPAllowed",
		"/api/cardInfo/appleCard/submit",
		"/api/cardInfo/appleCard/rechargeOrder/handler",
		"/api/cardInfo/appleCard/query",
		"/api/cardInfo/walmart/account/load",
		"/api/cardInfo/appleCard/rechargeOrder/callback",
		"/api/recharge/tMallGame/agiso/callback",
		"/api/recharge/tMallGame/account/getOneByRandom",
		"/api/recharge/tMallGame/order/submit",
		"/api/recharge/tMallGame/account/auth/callback",
		"/api/recharge/tMallGame/data/sync",
		"/api/recharge/tMallGame/order/queryOne",
		"/api/cardInfo/JDCard/order/submit",
		"/api/cardInfo/walmart/order/submit",
		"/api/cardInfo/cTrip/order/submit",
		"/api/restriction/collection/userInfo",
		"/api/restriction/collection/userInfo",
		"/api/cookieInfo/jd/order/placeOrder",
		"/api/jd-cookie/order/create",
		"/api/jd-v2/order/submit",
	}
	internalWhiteListAuth := []string{
		"/api/aes/encryption/params",
	}
	// 判断 ip
	if slices.Contains(internalWhiteListAuth, r.URL.Path) && netutil.IsInternalIP(net.ParseIP(r.GetClientIp())) {
		return gcode.CodeOK
	}

	whiteSet := gset.NewStrSet(true)
	whiteSet.Add(whiteList...)
	if whiteSet.Contains(r.URL.Path) {
		return gcode.CodeOK
	}
	return gcode.CodeNotAuthorized
}

func loginAuth(r *ghttp.Request) gcode.Code {
	//	获取Token
	tokenStr := token.GetRequestToken(r)
	if tokenStr == "" {
		return gcode.New(errHandler.ErrTokenError.Code(), "获取Token失败", nil)
	}
	userToken, err := token.ParseUserToken(r.GetCtx(), tokenStr)
	if err != nil {
		glog.Error(r.GetCtx(), "校验Token失败，当前Token", tokenStr, "错误码：", err)
		return gcode.New(errHandler.ErrTokenError.Code(), "校验Token失败", nil)
	}
	// 查看redis中是否有token
	oldTokenStr, err := token.GetTokenFromRedis(r.GetCtx(), userToken.UserID, userToken.ID)
	if err != nil {
		glog.Error(r.GetCtx(), "校验Token失败", err)
		return gcode.New(errHandler.ErrTokenError.Code(), "校验Token失败", nil)
	}
	if oldTokenStr != tokenStr {
		glog.Error(r.GetCtx(), "校验Token失败", err)
		return gcode.New(errHandler.ErrTokenError.Code(), "当前Token失效", nil)
	}
	// 续签token
	newToken, err := token.RefreshUserToken(r.GetCtx(), *userToken)
	if err != nil {
		glog.Error(r.GetCtx(), "续签Token失败", err)
		return gcode.New(errHandler.ErrTokenError.Code(), "续签Token失败", nil)
	}
	if newToken != "" {
		r.Response.Header().Set("refresh-token", newToken)
	}
	return gcode.CodeOK
}

func iFrameAuth(r *ghttp.Request) gcode.Code {
	tokenStr := token.GetRequestToken(r)
	if tokenStr == "" {
		return gcode.New(errHandler.ErrTokenError.Code(), "Token不存在,请刷新页面!", nil)
	}
	ctx := r.GetCtx()
	frontendModel, err := service.SysConfigDict().GetAESKeyBytes(ctx)
	if err != nil {
		return gcode.New(errHandler.ErrTokenError.Code(), "解析Token错误!", nil)
	}
	tokenByte, err := verify.AesCBCURLDecryptWithBase64(tokenStr, frontendModel.Key, frontendModel.IV)
	if err != nil {
		return gcode.New(errHandler.ErrTokenError.Code(), "解析Token错误!", nil)
	}
	tokenStruct := struct {
		CurrentTime int64  `json:"currentTime"`
		UserId      string `json:"userId"`
		UserAuth    string `json:"userAuth"`
	}{}
	if err = gjson.DecodeTo(tokenByte, &tokenStruct); err != nil {
		glog.Error(ctx, "解析Token错误", tokenStr, err)
		return gcode.New(errHandler.ErrTokenError.Code(), "Token格式错误!", nil)
	}
	if time.Since(time.Unix(tokenStruct.CurrentTime, 0)) > time.Minute*30 {
		return gcode.New(errHandler.ErrTokenError.Code(), "token失效，请刷新页面!", nil)
	}
	return gcode.CodeOK
}

func LoginOrIframeAuth(r *ghttp.Request) {
	if whiteListAuth(r) == gcode.CodeOK {
		r.Middleware.Next()
		return
	}
	tokenFrom := r.Request.Header.Get("tokenFrom")
	if gstr.ToLower(tokenFrom) == "login" {
		code := loginAuth(r)
		if code != gcode.CodeOK {
			r.Response.WriteJson(ghttp.DefaultHandlerResponse{
				Code:    code.Code(),
				Message: code.Message(),
				Data:    code.Detail(),
			})
			return
		}
		r.Middleware.Next()
		return
	}
	if gstr.ToLower(tokenFrom) == "iframe" {
		code := iFrameAuth(r)
		if code != gcode.CodeOK {
			r.Response.WriteJson(ghttp.DefaultHandlerResponse{
				Code:    code.Code(),
				Message: code.Message(),
				Data:    code.Detail(),
			})
			return
		}
		r.Middleware.Next()
		return
	}
	r.Response.WriteJson(ghttp.DefaultHandlerResponse{
		Code:    errHandler.ErrTokenError.Code(),
		Message: "token来源不明",
	})
}
