package api

import (
	"regexp"
	"shop-api/global"
	"shop-api/middleware"
	"shop-api/model"
	"shop-api/model/request"
	"shop-api/model/response"
	"shop-api/service"
	"time"

	"shop-api/utils"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis"
	"go.uber.org/zap"
)

// Login
// @Summary 普通登录[v1.0.0]
// @Security Bearer
// @Description
// @Tags auth
// @Param data body request.UserLogin true "email,password..."
// @Success 200 {string} string "{"code": 0, "data": [...]}"
// @Success 200 {string} string "{"code": 1, "message": ""}"
// @Router /base/login [post]
func Login(c *gin.Context) {
	var (
		err  error
		l    request.UserLogin
		user *model.User
	)
	_ = c.ShouldBindJSON(&l)
	if err := utils.Verify(l, utils.LoginVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if l.Type == "1" {
		if err := utils.Verify(l, utils.LoginPhoneVerify); err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
		//校验手机号格式
		if ok, _ := regexp.MatchString(utils.RegPhoneNumber, l.Phone); !ok {
			response.FailWithMessage("手机号码格式不合法", c)
			return
		}
	} else if l.Type == "2" {
		if err := utils.Verify(l, utils.LoginEmailVerify); err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
		//校验邮箱格式
		if ok, _ := regexp.MatchString(utils.RegEmailNumber, l.Email); !ok {
			response.FailWithMessage("邮箱格式不合法", c)
			return
		}
	} else {
		response.FailWithMessage("登录类型不合法", c)
		return
	}
	if err, user = service.UserLogin(&l); err != nil {
		global.MG_LOG.Error("Login failed! The user name does not exist or the password is wrong!", zap.Any("err", err))
		response.FailWithMessage("The user name does not exist or the password is wrong", c)
		return
	}
	// if user.IDForbidden {
	// 	response.OkWithDetailed(map[string]interface{}{"id_forbidden": user.IDForbidden, "forbidden_time": user.ForbiddenTime.Unix(), "forbidden_reason": user.ForbiddenReason}, "The user forbidden", c)
	// 	return
	// }
	tokenNext(c, *user)
}

// Register
// @Summary 注册[v1.0.0]
// @Description
// @Tags auth
// @Param data body request.UserRegister true "email,password..."
// @Success 200 {string} string "{"code": 0, "data": "注册成功"}"
// @Success 200 {string} string "{"code": 1, "message": ""}"
// @Router /base/register [post]
func Register(c *gin.Context) {
	var (
		err  error
		l    request.UserRegister
		user *model.User
	)
	_ = c.ShouldBindJSON(&l)
	if err := utils.Verify(l, utils.RegisterVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//校验邮箱格式
	if ok, _ := regexp.MatchString(utils.RegEmailNumber, l.Email); !ok {
		response.FailWithMessage("邮箱格式不合法", c)
		return
	}
	if err, user = service.UserRegister(&l); err != nil {
		global.MG_LOG.Error("Register failed!", zap.Any("err", err))
		response.FailWithMessage(err.Error(), c)
		return
	}
	tokenNext(c, *user)
}

// 登录以后签发jwt
func tokenNext(c *gin.Context, user model.User) {
	j := &middleware.JWT{SigningKey: []byte(global.MG_CONFIG.JWT.SigningKey)} // 唯一签名
	claims := request.UserClaims{
		UUID:        user.UUID.String(),
		Email:       user.Email,
		Appid:       user.Appid,
		Type:        user.Type,
		IDForbidden: user.IDForbidden,
		BufferTime:  global.MG_CONFIG.JWT.BufferTime, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix() - 1000,                             // 签名生效时间
			ExpiresAt: time.Now().Unix() + global.MG_CONFIG.JWT.ExpiresTime, // 过期时间 7天  配置文件
			Issuer:    "qmPlus",                                             // 签名的发行者
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
		global.MG_LOG.Error("get token field!", zap.Any("err", err))
		response.FailWithMessage("get token field", c)
		return
	}
	if global.MG_CONFIG.System.UseMultipoint {
		err, jwtStr := service.GetRedisJWT(user.Username)
		if err == redis.Nil {
			if err := service.SetRedisJWT(token, user.Username); err != nil {
				global.MG_LOG.Error("set token failed!", zap.Any("err", err))
				response.FailWithMessage("set token failed", c)
				return
			}
		} else if err != nil {
			global.MG_LOG.Error("get token failed!", zap.Any("err", err))
			response.FailWithMessage("get token failed", c)
			return
		} else {
			if err := service.JsonInBlacklist(model.JwtBlacklist{Jwt: jwtStr}); err != nil {
				global.MG_LOG.Error("jwt作废失败!", zap.Any("err", err))
				response.FailWithMessage("jwt作废失败", c)
				return
			}
			if err := service.SetRedisJWT(token, user.Username); err != nil {
				global.MG_LOG.Error("设置登录状态失败!", zap.Any("err", err))
				response.FailWithMessage("设置登录状态失败", c)
				return
			}
		}
	}
	// if !global.MG_CONFIG.System.UseMultipoint {
	response.OkWithDetailed(response.LoginResponse{
		User: model.UserSimple{
			UUID:     user.UUID,
			NickName: user.NickName,
			Avatar:   user.Avatar,
			Tags:     user.Tags,
		},
		Token:     token,
		ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
	}, "success", c)
}

// @Summary 授权登录[v1.0.0]
// @Description
// @Tags auth
// @Param data body request.UserAuthorized true "email,password..."
// @Success 200 {object} response.LoginResponse "{"code": 0, "data": "获取成功"}"
// @Success 200 {string} string "{"code": 1, "message": ""}"
// @Router /base/authorized [post]
func Authorized(c *gin.Context) {
	var (
		err  error
		l    request.UserAuthorized
		user model.User
	)
	_ = c.ShouldBindJSON(&l)
	if user, err = service.UserAuthorized(&l); err != nil {
		global.MG_LOG.Error("Authorized failed!", zap.Any("err", err))
		response.FailWithMessage(err.Error(), c)
		return
	}
	tokenNext(c, user)
}

// @Summary 获取第三方登录列表[v1.0.0]
// @Security Bearer
// @Description
// @Tags auth
// @Param data query request.AppProvider true "email,password..."
// @Success 200 {object} model.ProviderSimple "{"code": 0, "data": "获取成功"}"
// @Success 200 {string} string "{"code": 1, "message": ""}"
// @Router /base/provider [get]
func GetProviderList(c *gin.Context) {
	var (
		l request.AppProvider
	)
	_ = c.ShouldBind(&l)
	if data, err := service.GetProviderList(&l); err != nil {
		global.MG_LOG.Error("GetProviderList failed!", zap.Any("err", err))
		response.FailWithMessage(err.Error(), c)
		return
	} else {
		response.OkWithData(data, c)
	}
}

// @Summary 获取第三方登录信息[v1.0.0]
// @Security Bearer
// @Description
// @Tags auth
// @Param data query request.ProviderAuth true "provider"
// @Success 200 {object} string "{"code": 0, "data": "获取成功"}"
// @Success 200 {string} string "{"code": 1, "message": ""}"
// @Router /base/authUrl [get]
func GetProviderAuthUrl(c *gin.Context) {
	var (
		err error
		l   request.ProviderAuth
	)
	_ = c.ShouldBind(&l)
	if err := utils.Verify(l, utils.RegisterVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err, data := service.GetProviderAuthUrl(&l)
	if err != nil {
		global.MG_LOG.Error("GetProviderAuthUrl failed!", zap.Any("err", err))
		response.FailWithMessage(err.Error(), c)
		return
	} else {
		response.OkWithData(data, c)
	}
}

// GetChainInfo
// @Summary 获取区块链数据
// @Description
// @Tags Chain
// @Param data query request.ChainParams false "data..."
// @Success 200 {object} []response.ChainResp "{"code": 0, "data": [...]}"
// @Success 201 {string} string "{"code": 1, "message": ""}"
// @Router /base/chain [get]
func GetChainInfo(c *gin.Context) {
	var (
		err    error
		params request.ChainParams
		result []response.ChainResp
	)
	_ = c.ShouldBindQuery(&params)
	if err := utils.Verify(params, utils.ChainVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err, result = service.GetChainInfo(params.Hash)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithDataMessage(result, "success", c)
}