package app

import (
	"ln/nft/global"
	"ln/nft/model/app"
	appReq "ln/nft/model/app/request"
	appRes "ln/nft/model/app/response"
	"ln/nft/model/common/response"
	"ln/nft/model/system"
	systemReq "ln/nft/model/system/request"
	"ln/nft/utils"

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

// @Tags User
// @Summary 用户注册账号
// @Produce  application/json
// @Param data body systemReq.Register true "电子邮箱, 验证码, 密码"
// @Success 200 {object} response.Response{data=systemRes.UserResponse,msg=string} "用户注册账号,返回包括用户信息"
// @Router /user/admin_register [post]
func (b *BaseApi) Register(c *gin.Context) {
	var r appReq.Register
	_ = c.ShouldBindJSON(&r)
	var verify map[string][]string
	if r.Email != "" { // 邮箱注册
		verify = utils.RegisterVerifyEmail
	} else { // 手机号注册
		verify = utils.RegisterVerifyPhone
	}
	if err := utils.Verify(r, verify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var authorities []app.Authority
	for _, v := range r.AuthorityIds {
		authorities = append(authorities, app.Authority{
			AuthorityId: v,
		})
	}
	user := &app.User{Email: r.Email, Password: r.Password, AuthorityId: r.AuthorityId, Authorities: authorities}
	userReturn, err := userService.Register(*user)
	if err != nil {
		global.GVA_LOG.Error("注册失败", zap.Error(err))
		response.FailWithDetailed(appRes.UserResponse{User: userReturn}, err.Error(), c)
	} else {
		response.OkWithDetailed(appRes.UserResponse{User: userReturn}, "注册成功", c)
	}

}

// @Tags Base
// @Summary 用户登录
// @Produce  application/json
// @Param data body systemReq.Login true "电子邮箱/手机号, 验证码/密码"
// @Success 200 {object} response.Response{data=systemRes.LoginResponse,msg=string} "返回包括用户信息,token,过期时间"
// @Router /base/login [post]
func (b *BaseApi) Login(c *gin.Context) {
	var l appReq.Login
	_ = c.ShouldBindJSON(&l)
	if err := utils.Verify(l, utils.LoginVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	u := &app.User{Email: l.Email, Phone: l.Phone, Password: l.Password}
	if user, err := userService.Login(u); err != nil {
		global.GVA_LOG.Error("登陆失败! 账号不存在或者密码错误!", zap.Error(err))
		response.FailWithMessage("账号不存在或者密码错误", c)
	} else {
		if user.Enable != 1 {
			global.GVA_LOG.Error("登陆失败! 用户被禁止登录!")
			response.FailWithMessage("用户被禁止登录", c)
			return
		}
		b.TokenNext(c, *user)
	}
}

// 登录以后签发jwt
func (b *BaseApi) TokenNext(c *gin.Context, user app.User) {
	j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名
	claims := j.CreateClaims(systemReq.BaseClaims{
		UUID:        user.UUID,
		ID:          user.ID,
		NickName:    user.NickName,
		Email:       user.Email,
		Phone:       user.Phone,
		AuthorityId: user.AuthorityId,
	})
	token, err := j.CreateToken(claims)
	if err != nil {
		global.GVA_LOG.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	if !global.GVA_CONFIG.System.UseMultipoint {
		response.OkWithDetailed(appRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
		return
	}

	if jwtStr, err := jwtService.GetRedisJWT(user.Email + user.Phone); err == redis.Nil {
		if err := jwtService.SetRedisJWT(token, user.Email+user.Phone); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(appRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	} else if err != nil {
		global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT system.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := jwtService.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := jwtService.SetRedisJWT(token, user.Email+user.Phone); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(appRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	}
}

// @Tags User
// @Summary 用户修改密码
// @Security ApiKeyAuth
// @Produce  application/json
// @Param data body appReq.ChangePasswordStruct true "原密码, 新密码"
// @Success 200 {object} response.Response{msg=string} "用户修改密码"
// @Router /user/changePassword [post]
func (b *BaseApi) ChangePassword(c *gin.Context) {
	var user appReq.ChangePasswordStruct
	_ = c.ShouldBindJSON(&user)
	if err := utils.Verify(user, utils.AppChangePasswordVerify); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	claims := c.MustGet("claims").(*systemReq.CustomClaims)
	u := &app.User{Password: user.Password, UUID: claims.UUID}
	if _, err := userService.ChangePassword(u, user.NewPassword); err != nil {
		global.GVA_LOG.Error("修改失败!", zap.Error(err))
		response.FailWithMessage("修改失败，原密码与当前账户不符", c)
	} else {
		response.OkWithMessage("修改成功", c)
	}
}
