package api

import (
	"errors"
	"fmt"
	"github.com/golang-jwt/jwt/v4"
	"github.com/jakehl/goid"
	"github.com/kataras/iris/v12"
	"github.com/sirupsen/logrus"
	"main/database"
	"main/jwtSet"
	"main/model"
	"main/service/admin"
	"main/utils"
	"math/rand"
	"strconv"
	"strings"
	"time"
)

// 返回加密后用户信息
func userinfo(ctx iris.Context) {
	user := utils.GetLoginUser(ctx)
	if utils.DataIsNil(user) {
		return
	}
	if user.Email != "" {
		user.Email = fmt.Sprintf("%s****%s", user.Email[0:2], user.Email[len(user.Email)-7:])
	}
	if user.Mobile != "" {
		user.Mobile = fmt.Sprintf("%s****%s", user.Mobile[0:2], user.Mobile[len(user.Mobile)-4:])
	}
	err := ctx.JSON(utils.FormatRes(iris.StatusOK, "", user))
	if utils.ErrHandle(ctx, err) {
		return
	}
}

// 更新用户信息
func updateUserinfo(ctx iris.Context) {
	username := utils.GetLoginUser(ctx)
	if utils.DataIsNil(username) {
		return
	}
	var params model.Userinfo
	err := ctx.ReadJSON(&params)
	if utils.ErrHandle(ctx, err) {
		return
	}
	db := database.GetInstance().GetMysqlDb()
	if strings.Contains(params.Email, "*") {
		params.Email = ""
	}
	if strings.Contains(params.Mobile, "*") {
		params.Mobile = ""
	}
	if err1 := db.Model(&model.Userinfo{}).Where("username = ?", username.Username).Updates(params).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	for i, u := range utils.UserList {
		if u.Username == username.Username {
			utils.UserList[i] = params
		}
	}
	utils.UpdateUserInfo()
	err = ctx.JSON(utils.FormatRes(iris.StatusOK, "", "success"))
	if utils.ErrHandle(ctx, err) {
		return
	}
}

// 用户登录
func login(ctx iris.Context) (string, error) {
	username := ctx.URLParam("username")
	password := ctx.URLParam("password")
	confirmCode := ctx.URLParam("confirmCode")
	auto := ctx.URLParam("auto")
	var res result
	db := database.GetInstance().GetMysqlDb()
	if err := db.
		Model(&model.User{}).
		Select("users.password, users.confirm_code, users.updated_at, day_keys.key, day_keys.aes_key").
		Joins("left join day_keys on day_keys.user = users.username and day_keys.date = users.date").
		Where("users.username = ?", username).
		Order("users.date desc").
		Scan(&res).Error; err != nil {
		logrus.Errorln("sql执行失败：", err)
	}
	if utils.DataIsNil(res) {
		return "", errors.New("用户不存在")
	}
	rsaDePass, err := utils.RsaDecrypt(password, res.Key)
	if err != nil {
		return "", err
	}
	if confirmCode == "" {
		aesDePass, err := utils.DecryptByAes(res.Password, []byte(res.AesKey))
		if err != nil {
			return "", err
		}
		//fmt.Println(string(aesDePass), rsaDePass)
		if string(aesDePass) != rsaDePass {
			return "", errors.New("用户信息错误")
		}
	} else if res.ConfirmCode != confirmCode {
		return "", errors.New("验证码错误")
	} else if res.ConfirmCode != "" && time.Now().After(res.UpdatedAt.Add(time.Minute*5)) {
		return "", errors.New("验证码已过期")
	}
	priKeys, _ := utils.GetPrivateKeys(username, time.Now().Format("2006-01-02"))
	newPwd, _ := utils.EncryptByAes([]byte(rsaDePass), []byte(priKeys.AesKey))
	if err1 := db.
		Model(&model.User{}).
		Where("username = ?", username).
		Updates(map[string]interface{}{
			"password":     newPwd,
			"date":         time.Now().Format("2006-01-02"),
			"confirm_code": "",
		}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	rand1 := rand.New(rand.NewSource(time.Now().UnixNano()))
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": username,
		"iat":      time.Now().Unix(),
		"jti":      strconv.Itoa(rand1.Int()),
		"exp":      time.Now().Add(2 * time.Hour).Unix(),
	})
	jwtKey := jwtSet.GetJwtKeys().Key
	tokenString, err := token.SignedString([]byte(jwtKey))
	if err != nil {
		return "", err
	}
	ctx.SetCookieKV("is_login", "1", iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	ctx.SetCookieKV("token", tokenString, iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	ctx.SetCookieKV("loginTime", strconv.FormatInt(time.Now().UnixMilli(), 10), iris.CookieHTTPOnly(false))
	if err1 := db.Create(&model.UserAction{
		Username: username,
		Action:   "用户登录",
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if err1 := db.Create(&model.JwtKeys{
		Username: username,
		Date:     time.Now().Format("2006-01-02"),
		Key:      jwtKey,
		Token:    tokenString,
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if auto == "true" {
		deviceId := goid.NewV4UUID()
		location := admin.GetIpLocation(utils.GetRequestIp(ctx))
		ctx.SetCookieKV("deviceId", deviceId.String(), iris.CookieHTTPOnly(false))
		if err1 := db.Create(&model.UserAutoLogin{
			Username: username,
			DeviceId: deviceId.String(),
			Location: location,
		}).Error; err1 != nil {
			logrus.Errorln("sql执行失败：", err1)
		}
	}
	return tokenString, nil
}

// 用户注册
func register(ctx iris.Context) (string, error) {
	username := ctx.URLParam("username")
	password := ctx.URLParam("password")
	priKeys, err := utils.GetPrivateKeys(username, time.Now().Format("2006-01-02"))
	if err != nil {
		return "", err
	}
	dePass, err := utils.RsaDecrypt(password, priKeys.Key)
	if err != nil {
		return "", err
	}
	enPass, err := utils.EncryptByAes([]byte(dePass), []byte(priKeys.AesKey))
	if err != nil {
		return "", err
	}
	db := database.GetInstance().GetMysqlDb()
	var user []model.User
	if err1 := db.Where("username = ?", username).Find(&user).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if len(user) > 0 {
		err = errors.New("user exists")
		return "", err
	}
	if err1 := db.Create(&model.User{
		Username: username,
		Password: enPass,
		Date:     time.Now().Format("2006-01-02"),
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if len(utils.UserList) == 0 {
		if err1 := db.Create(&model.Userinfo{
			Username: username,
			Type:     "admin",
		}).Error; err1 != nil {
			logrus.Errorln("sql执行失败：", err1)
		}
	} else {
		if err1 := db.Create(&model.Userinfo{
			Username: username,
			Type:     "user",
		}).Error; err1 != nil {
			logrus.Errorln("sql执行失败：", err1)
		}
	}
	utils.UpdateUserInfo()
	rand1 := rand.New(rand.NewSource(time.Now().UnixNano()))
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": username,
		"iat":      time.Now().Unix(),
		"jti":      strconv.Itoa(rand1.Int()),
		"exp":      time.Now().Add(2 * time.Hour).Unix(),
	})
	jwtKey := jwtSet.GetJwtKeys().Key
	tokenString, err := token.SignedString([]byte(jwtKey))
	if err != nil {
		return "", err
	}
	ctx.SetCookieKV("is_login", "1", iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	ctx.SetCookieKV("token", tokenString, iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	ctx.SetCookieKV("loginTime", strconv.FormatInt(time.Now().UnixMilli(), 10), iris.CookieHTTPOnly(false))
	if err1 := db.Create(&model.UserAction{
		Username: username,
		Action:   "用户注册并登录",
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if err1 := db.Create(&model.JwtKeys{
		Username: username,
		Date:     time.Now().Format("2006-01-02"),
		Key:      jwtKey,
		Token:    tokenString,
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	return tokenString, nil
}

// 退出登录
func logout(ctx iris.Context) {
	db := database.GetInstance().GetMysqlDb()
	username := utils.GetLoginUser(ctx)
	auth := ctx.Values().Get("jwt")
	deviceId := ctx.GetCookie("deviceId")
	if auth == nil {
		ctx.StatusCode(iris.StatusUnauthorized)
		ctx.SetErr(errors.New("未登录"))
		return
	}
	if err := db.Where("token = ?", auth.(*jwt.Token).Raw).Delete(&model.JwtKeys{}).Error; err != nil {
		logrus.Errorln("sql执行失败：", err)
	}
	ctx.RemoveCookie("is_login")
	ctx.RemoveCookie("token")
	if deviceId != "" {
		ctx.RemoveCookie("deviceId")
		if err := db.Where("device_id = ? and username = ?", deviceId, username).Delete(&model.UserAutoLogin{}).Error; err != nil {
			logrus.Errorln("sql执行失败：", err)
		}
	}
	if err := db.Create(&model.UserAction{
		Username: username.Username,
		Action:   "用户注销登录",
	}).Error; err != nil {
		logrus.Errorln("sql执行失败：", err)
	}
	err := ctx.JSON(utils.FormatRes(iris.StatusOK, "", "success"))
	if utils.ErrHandle(ctx, err) {
		return
	}
}

// 重置密码
func resetPwd(ctx iris.Context) {
	username := ctx.URLParam("username")
	//var user model.Userinfo
	db := database.GetInstance().GetMysqlDb()
	user := utils.GetUserInfo(username)
	if utils.DataIsNil(user) {
		ctx.StatusCode(iris.StatusInternalServerError)
		ctx.SetErr(errors.New("用户不存在"))
		return
	}
	confirmCode := utils.NewKey(8)
	if err := db.Model(&model.User{}).Where("username = ?", username).Updates(model.User{ConfirmCode: confirmCode}).Error; err != nil {
		logrus.Errorln("sql执行失败：", err)
	}
	err := utils.SendEmail([]string{user.Email}, "密码重置", fmt.Sprintf("验证码为：%s\n您正在进行密码重置，验证码5分钟内有效，如非本人操作，请忽略本邮件", confirmCode))
	if utils.ErrHandle(ctx, err) {
		return
	}
	if err1 := db.Create(&model.UserAction{
		Username: username,
		Action:   "获取重置密码验证码",
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	err = ctx.JSON(utils.FormatRes(iris.StatusOK, "", fmt.Sprintf("%s****%s", user.Email[0:2], user.Email[7:])))
	if utils.ErrHandle(ctx, err) {
		return
	}
}

func autoLogin(ctx iris.Context) {
	var user []model.UserAutoLogin
	location := admin.GetIpLocation(utils.GetRequestIp(ctx))
	deviceId := ctx.GetCookie("deviceId")
	if deviceId == "" || location == "" {
		err := ctx.JSON(utils.FormatRes(iris.StatusOK, "自动登录未设置", false))
		if utils.ErrHandle(ctx, err) {
			return
		}
		return
	}
	db := database.GetInstance().GetMysqlDb()
	if err := db.Where("device_id = ? and location = ?", deviceId, location).Find(&user).Error; err != nil {
		logrus.Errorln("sql执行失败：", err)
	}
	if len(user) == 0 {
		err := ctx.JSON(utils.FormatRes(iris.StatusOK, "自动登录未设置", false))
		if utils.ErrHandle(ctx, err) {
			return
		}
		return
	}
	rand1 := rand.New(rand.NewSource(time.Now().UnixNano()))
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": user[0].Username,
		"iat":      time.Now().Unix(),
		"jti":      strconv.Itoa(rand1.Int()),
		"exp":      time.Now().Add(2 * time.Hour).Unix(),
	})
	jwtKey := jwtSet.GetJwtKeys().Key
	tokenString, err := token.SignedString([]byte(jwtKey))
	if utils.ErrHandle(ctx, err) {
		return
	}
	ctx.SetCookieKV("is_login", "1", iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	ctx.SetCookieKV("token", tokenString, iris.CookieHTTPOnly(false), iris.CookieExpires(2*time.Hour))
	if err1 := db.Create(&model.UserAction{
		Username: user[0].Username,
		Action:   "用户自动登录",
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	if err1 := db.Create(&model.JwtKeys{
		Username: user[0].Username,
		Date:     time.Now().Format("2006-01-02"),
		Key:      jwtKey,
		Token:    tokenString,
	}).Error; err1 != nil {
		logrus.Errorln("sql执行失败：", err1)
	}
	err = ctx.JSON(utils.FormatRes(iris.StatusOK, "", tokenString))
	if utils.ErrHandle(ctx, err) {
		return
	}
}
