package controllers

import (
	"ai_developer_admin/libs/jose"
	"ai_developer_admin/libs/kong"
	"ai_developer_admin/libs/mysql"
	"ai_developer_admin/libs/odysseus"
	"ai_developer_admin/libs/redis"
	"ai_developer_admin/libs/utils"
	"ai_developer_admin/models"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"github.com/beego/beego/v2/core/logs"
	beego "github.com/beego/beego/v2/server/web"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type UserController struct {
	MainController
}

//func (u *UserController) respond(code int, message string, data ...interface{}) {
//	u.Ctx.Output.SetStatus(code)
//	var d interface{}
//	if len(data) > 0 {
//		d = data[0]
//	}
//	u.Data["json"] = struct {
//		Code    int         `json:"code"`
//		Message string      `json:"message"`
//		Data    interface{} `json:"data,omitempty"`
//	}{
//		Code:    code,
//		Message: message,
//		Data:    d,
//	}
//	u.ServeJSON()
//}

//func (u *UserController) Test() {
//	info, err := u.Check()
//	if err != nil {
//		u.respond(http.StatusUnauthorized, err.Error())
//		return
//	}
//	u.respond(http.StatusOK, "", info)
//}

func (server *UserController) Login() {
	var err error
	body := server.Ctx.Input.RequestBody
	loginRequest := models.LoginRequest{}
	err = json.Unmarshal(body, &loginRequest) //解析body中数据
	logs.Debug("loginRequest", loginRequest)
	if err != nil {
		server.respond(models.NoRequestBody, err.Error())
		return
	}
	//if len(user.Username) == 0 {
	//	u.respond(http.StatusBadRequest, "用户名不能为空")
	//	return
	//}

	claims, err := jose.Verify("https://api-auth.web3auth.io/jwks", loginRequest.Web3AuthPublicKey, loginRequest.IdToken)
	if err != nil {
		server.respond(models.LoginFailed, "Web3Auth verify failed")
		return
	}

	if claims.Exp <= time.Now().Unix() {
		server.respond(models.LoginFailed, "Web3Auth login expire")
		return
	}

	clientId, _ := beego.AppConfig.String("web3ClientId")

	if strings.Compare(clientId, claims.Aud) != 0 {
		server.respond(models.LoginFailed, "web3auth clientId error")
		return
	}

	user := loginRequest.RequstUser
	//if len(user.VerifierId) == 0 {
	user.VerifierId = claims.VerifierId
	//}
	if len(user.Username) == 0 {
		user.Username = "ai_" + generatorMD5(user.Mail)[0:8]
	}
	if len(user.ProfileImage) == 0 {
		user.ProfileImage = claims.ProfileImage
	}

	checkUser := &models.User{Mail: user.Mail}
	err = mysql.GetMysqlInstace().Ormer.Read(checkUser, "mail")
	stats := mysql.Ping()
	if stats != nil {
		server.respond(models.CreateUserFailed, stats.Error())
		return
	}
	if err != nil && stats == nil {
		checkUser, err = regisgerUser(user)
		if checkUser == nil {
			server.respond(models.CreateUserFailed, err.Error())
			return
		}
	}
	key := "token:user-" + strconv.Itoa(checkUser.Id)
	session, err := redis.GetDataToString(key)
	if session != "" {
		server.Ctx.Output.Header("Authorization", session)
		server.respond(http.StatusOK, "")
		return
	}
	//duration := claims.Exp - claims.Iat
	duration := utils.DEFAULT_EXPIRE_SECONDS
	tokenString, err := utils.GenerateToken(checkUser, checkUser.Id, duration)
	if err != nil {
		server.respond(models.LoginFailed, "failed")
		return
	}
	//checkUserLevel := &models.UserLevel{Id: checkUser.LevelId}
	//err = mysql.GetMysqlInstace().Ormer.Read(checkUserLevel)
	//if err != nil {
	//	logs.Debug("Recharge 用户等级查找失败")
	//} else {
	//	odysseus.SyncCredit(strconv.Itoa(checkUser.Id), checkUserLevel.FreeQuota)
	//}

	//u.SetSession(key, tokenString)
	//lifetime, _ := beego.AppConfig.Int64("sessiongcmaxlifetime")
	redis.SetKeyAndData(key, tokenString, time.Duration(duration)*time.Second)
	server.Ctx.Output.Header("Authorization", tokenString) // set token into header
	//session := u.GetSession(key)
	//logs.Debug("login session", session)

	server.respond(http.StatusOK, "")
}

func (server *UserController) Logout() {
	info, err := server.Check()
	if err != nil {
		server.respond(http.StatusUnauthorized, err.Error())
		return
	}
	key := "token:user-" + strconv.Itoa(info.UserID)
	redis.DeleteKey(key)
	server.respond(http.StatusUnauthorized, "")
}

func (server *UserController) Regisger() {
	var err error
	user := models.User{}
	body := server.Ctx.Input.RequestBody
	err = json.Unmarshal(body, &user) //解析body中数据
	logs.Debug("user", user)
	if err != nil {
		server.respond(models.NoRequestBody, err.Error())
		return
	}
	if len(user.Username) == 0 {
		server.respond(models.MissingParameter, "Missing username parameter")
		return
	}

	_, err = regisgerUser(user)
	if err != nil {
		server.respond(models.CreateUserFailed, err.Error())
		return
	}

	server.respond(http.StatusOK, "")
}

func (server *UserController) UserInfo() {
	info, err := server.Check()
	if err != nil {
		server.respond(http.StatusUnauthorized, err.Error())
		return
	}
	checkUser := &models.User{Id: info.UserID}
	err = mysql.GetMysqlInstace().Ormer.Read(checkUser)
	if err != nil {
		server.respond(models.BusinessFailed, err.Error())
		return
	}
	userBalance := checkUser.Balance
	balance, err := odysseus.GetUserBalance(int64(checkUser.Id))
	if err == nil {
		userBalance = balance
		if balance < 0 {
			userBalance = 0
		}
	}

	checkUserLevel := &models.UserLevel{Level: checkUser.Level}
	err = mysql.GetMysqlInstace().Ormer.Read(checkUserLevel, "level")
	creditQuota := int64(0)
	if err == nil {
		creditQuota = checkUserLevel.CreditQuota
		if balance < 0 {
			creditQuota = checkUserLevel.CreditQuota + balance
		}
	}

	userInfo := models.UserInfo{
		Id:           checkUser.Id,
		Name:         checkUser.Name,
		Username:     checkUser.Username,
		Mail:         checkUser.Mail,
		Phone:        checkUser.Phone,
		CustomId:     checkUser.CustomId,
		ChainAccount: checkUser.ChainAccount,
		Type:         checkUser.Type,
		IsAuthed:     checkUser.IsAuthed,
		Balance:      float64(userBalance / 1000000),
		Level:        checkUser.Level,
		ProfileImage: checkUser.ProfileImage,
		Role:         checkUser.Role,
		CreditQuota:  float64(creditQuota / 1000000),
	}
	server.respond(http.StatusOK, "", userInfo)
}

func regisgerUser(user models.User) (*models.User, error) {
	var err error
	qs := mysql.GetMysqlInstace().Ormer.QueryTable("user")
	usernameQs := qs.Filter("mail", user.Mail)
	var count int64
	count, err = usernameQs.Count()
	if count > 0 {
		return nil, errors.New("user is exist")
	}
	//if len(user.CustomId) > 0 {
	//	customIdQs := qs.Filter("custom_id", user.CustomId)
	//	count, err = customIdQs.Count()
	//	if count > 0 {
	//		return nil, errors.New("您指定的客户id已存在")
	//	}
	//}

	user.CreatedTime = time.Now()
	user.UpdatedTime = user.CreatedTime
	user.Level = 0
	user.Role = 4

	_, err = mysql.GetMysqlInstace().Ormer.Insert(&user)
	if err != nil {
		return nil, errors.New("create user failed")
	}

	checkUser := &models.User{Username: user.Username}
	err = mysql.GetMysqlInstace().Ormer.Read(checkUser, "username")
	if err != nil {
		return nil, errors.New("create user failed")
	}
	checkUser.CustomId = strconv.Itoa(checkUser.Id)

	data, err := kong.CreateUser(checkUser)
	if err != nil {
		mysql.GetMysqlInstace().Ormer.Delete(checkUser)
		return nil, err
	}
	if data.Id == "" {
		mysql.GetMysqlInstace().Ormer.Delete(checkUser)
		return nil, errors.New(data.Message)
	}

	checkUserLevel := &models.UserLevel{Level: checkUser.Level}
	err = mysql.GetMysqlInstace().Ormer.Read(checkUserLevel, "level")
	if err != nil {
		logs.Debug("Recharge 用户等级查找失败")
	} else {
		plugin, err := kong.SetRateLimit(checkUser, checkUserLevel, "")
		if err == nil {
			checkUser.RateLimitPluginId = plugin.Id
		}
	}

	mysql.GetMysqlInstace().Ormer.Update(checkUser)

	createApiKey(checkUser)
	createJWTToken(checkUser)

	return checkUser, nil
}

func createApiKey(checkUser *models.User) {
	data, err := kong.CreateApiKey(checkUser)
	if err != nil {
		return
	}
	if data.Id == "" {
		return
	}

	timestamp := time.Now()
	app := models.ApiKey{
		Name:        "test",
		ApiKey:      data.Key,
		UserId:      checkUser.Id,
		CreatedTime: timestamp,
		UpdatedTime: timestamp,
		Deleted:     0,
		ApiKeyId:    data.Id,
	}
	mysql.GetMysqlInstace().Ormer.Insert(&app)
}

func createJWTToken(checkUser *models.User) {
	data, store, err := kong.CreateJwt(checkUser)
	if err != nil {
		return
	}
	if data.Id == "" {
		return
	}

	jwtToken, err := utils.GenerateKongToken(data, "")
	if err != nil {
		jwtToken = ""
	}
	timestamp := time.Now()
	app := models.JwtToken{
		Name:          "test",
		JwtCredential: string(store),
		JwtToken:      jwtToken,
		UserId:        checkUser.Id,
		CreatedTime:   timestamp,
		UpdatedTime:   timestamp,
		Deleted:       0,
		JwtId:         data.Id,
	}

	mysql.GetMysqlInstace().Ormer.Insert(&app)
}

func generatorMD5(code string) string {
	MD5 := md5.New()
	_, _ = io.WriteString(MD5, code)
	return hex.EncodeToString(MD5.Sum(nil))
}
