package middleware

import (
	"eta/eta_mini_ht_api/common/component/cache"
	logger "eta/eta_mini_ht_api/common/component/log"
	"eta/eta_mini_ht_api/common/exception"
	"eta/eta_mini_ht_api/common/utils/jwt"
	"eta/eta_mini_ht_api/common/utils/redis"
	stringUtils "eta/eta_mini_ht_api/common/utils/string"
	"eta/eta_mini_ht_api/controllers"
	userService "eta/eta_mini_ht_api/domian/user"
	"eta/eta_mini_ht_api/service/user"
	"fmt"
	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"strings"
)

var (
	rdCache *cache.RedisCache
)

const (
	ILLEGALUSER   = "用户信息异常"
	UNAUTHORIZED  = "请重新登录"
	TOKENEXPIRED  = "token过期"
	LOGINREQURED  = "重新登录"
	FORBIDDEN     = "禁止访问"
	NOTFOUND      = "未找到"
	authorization = "Authorization"
	baseUrl       = "/htapi"
	Bearer        = "Bearer"
)

func rd() *cache.RedisCache {
	if rdCache == nil {
		rdCache = cache.GetInstance()
	}
	return rdCache
}

var publicRoutes = []string{
	"/auth/areaCodes",
	"/auth/wxAppid",
	"/auth/notice",
	"/auth/disclaimer",
	"/auth/refreshToken",
	"/auth/sendCode",
	"/user/bind_gzh",
	"/user/wx/notify",
	"/webhook/*",
}
var privateRoutes = []string{
	"/user/profile",
	"/user/followAnalyst",
	"/user/followAnalysts",
	"/user/followingAnalystList",
	"/user/readMessages",
	"/user/readMessage",
	"/user/feedback",
	"/user/checkFollowStatus",
	"/user/followingAnalysts",
	"/user/message",
	"/analyst/analystDetail",
	"/analyst/list",
	"/media/count",
	"/report/count",
}

func AuthMiddleware() web.FilterFunc {
	return func(ctx *context.Context) {
		path := ctx.Input.URL()
		logger.Info("请求路径:%v", path)
		if !allowed(path) {
			rep := unAuthorized()
			auth := ctx.Input.Header(authorization)
			if auth == "" {
				logger.Error("token信息不存在")
				_ = ctx.JSONResp(rep)
				return
			}
			parts := strings.Split(auth, " ")
			if len(parts) != 2 || parts[0] != Bearer {
				logger.Error("token参数不符合格式" + auth)
				_ = ctx.JSONResp(rep)
				return
			}
			info, err := jwt.CheckToken(parts[1])
			if err != nil {
				logger.Error("token无效:%v", err)
				_ = ctx.JSONResp(rep)
				return
			}
			//组装用户信息
			var userInfo user.User
			userInfo, err = user.GetUserByOpenId(info.OpenId)
			if err != nil {
				logger.Error("获取用户信息失败:%v", err)
				_ = ctx.JSONResp(illegalUser())
				return
			}
			//校验redis中是否合法
			redisToken := rd().GetString(redis.GenerateTokenKey(info.OpenId))
			if redisToken == "" {
				logger.Error("token无效:token已失效,自动退出登录")
				//重置用户状态为登出
				err = userService.UserLogout(userInfo.Id)
				if err != nil {
					logger.Error("重置用户状态失败:%v", err)
				}
				_ = ctx.JSONResp(LoginRequired())
				return
			}
			if redisToken != parts[1] {
				logger.Error("token无效:用户token已刷新")
				_ = ctx.JSONResp(tokenExpired())
				return
			}
			if needCheckLoginStatus(path) {
				if info.TokenType != jwt.AccessToken || info.Mobile == "-" || info.Mobile == "" {
					logger.Error("token信息异常,当前token类型为:%v", jwt.GuestToken)
					_ = ctx.JSONResp(LoginRequired())
					return
				}
			}
			//if userInfo.Mobile == "-" && path != baseUrl+"/auth/login" {
			//	logger.Error("用户手机号为空:%v", err)
			//	_ = ctx.JSONResp(illegalUser())
			//	return
			//}
			ctx.Input.SetData("user", userInfo)
			return
		}
		return
	}
}

func unAuthorized() controllers.BaseResponse {
	return controllers.BaseResponse{
		Ret:    401,
		Msg:    UNAUTHORIZED,
		ErrMsg: exception.GetMsg(exception.Unauthorized),
	}
}
func tokenExpired() controllers.BaseResponse {
	return controllers.BaseResponse{
		Ret:    408,
		Msg:    TOKENEXPIRED,
		ErrMsg: exception.GetMsg(exception.Unauthorized),
	}
}

func LoginRequired() controllers.BaseResponse {
	return controllers.BaseResponse{
		Ret:    408,
		Msg:    LOGINREQURED,
		ErrMsg: exception.GetMsg(exception.Unauthorized),
	}
}
func illegalUser() controllers.BaseResponse {
	return controllers.BaseResponse{
		Ret:    401,
		Msg:    ILLEGALUSER,
		ErrMsg: exception.GetMsg(exception.Unauthorized),
	}
}
func allowed(path string) bool {
	for _, p := range publicRoutes {
		if stringUtils.IsBlank(p) {
			continue
		}
		src := baseUrl + p
		if strings.HasSuffix(p, "*") {

			target := src[:len(src)-1]
			fmt.Println("target:" + target)
			if strings.HasPrefix(path, target) {
				return true
			}
		} else {
			if src == path {
				return true
			}
		}
	}
	return false
}

func needCheckLoginStatus(path string) bool {
	for _, p := range privateRoutes {
		if stringUtils.IsBlank(p) {
			continue
		}
		src := baseUrl + p
		if strings.HasSuffix(p, "*") {
			target := src[:len(src)-1]
			if strings.HasPrefix(path, target) {
				return true
			}
		} else {
			if src == path {
				return true
			}
		}
	}
	return false
}