package user

import (
	"context"
	"time"

	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/logs"
)

const (
	USERINFO = "user_info"
)

type UserInfo struct {
	Id         int
	UserId     string
	Passwd     string
	Nick       string
	Remark     string
	Ip         string
	Status     string
	Role       string
	RoleName   string
	CreateTime time.Time
	UpdateTime time.Time
	OtpSecret  string `json:"-"`
	OtpKey     string `json:"-"`
}

func GetUserInfoByUserID(ctx context.Context, userID string) UserInfo {
	o := orm.NewOrm()
	var userInfo UserInfo
	err := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("user_id", userID).OneWithCtx(ctx, &userInfo)
	if err != nil {
		logs.Error("get user info fail: ", err)
	}
	return userInfo
}

func UpdateOtpByUserID(ctx context.Context, userID, totpSecret, key string) error {
	o := orm.NewOrm()
	_, err := o.QueryTable(USERINFO).Exclude("status", "delete").
		Filter("user_id", userID).
		UpdateWithCtx(ctx, orm.Params{"otp_secret": totpSecret, "otp_key": key})

	if err != nil {
		logs.Error("更新totp失败", err)
	}

	return err
}

func GetOperatorByMap(ctx context.Context, params map[string]string, displayCount, offset int) []UserInfo {
	o := orm.NewOrm()
	var userInfo []UserInfo
	qs := o.QueryTable(USERINFO)
	for k, v := range params {
		if len(v) > 0 {
			qs = qs.Filter(k, v)
		}
	}
	_, err := qs.Exclude("status", "delete").Limit(displayCount, offset).OrderBy("-update_time").AllWithCtx(ctx, &userInfo)

	if err != nil {
		logs.Error("get operator by map fail: ", err)
	}
	return userInfo
}

func GetOperatorLenByMap(ctx context.Context, params map[string]string) int {
	o := orm.NewOrm()
	qs := o.QueryTable(USERINFO)
	for k, v := range params {
		qs = qs.Filter(k, v)
	}
	cnt, err := qs.Exclude("status", "delete").CountWithCtx(ctx)
	if err != nil {
		logs.Error("get operator len by map fail: ", err)
	}
	return int(cnt)
}

func UpdateUserInfoIP(ctx context.Context, userInfo UserInfo) {
	o := orm.NewOrm()
	num, err := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("user_id", userInfo.UserId).UpdateWithCtx(ctx, orm.Params{"ip": userInfo.Ip})
	if err != nil {
		logs.Error("%s update user info ip fail: %v", userInfo.UserId, err)
	} else {
		logs.Info("%s update user info ip success, num: %d", userInfo.UserId, num)
	}
}

func UpdateUserInfoPassword(ctx context.Context, userInfo UserInfo) {
	o := orm.NewOrm()
	num, err := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("user_id", userInfo.UserId).UpdateWithCtx(ctx, orm.Params{"passwd": userInfo.Passwd})
	if err != nil {
		logs.Error("%s update user info password fail: %v", userInfo.UserId, err)
	} else {
		logs.Info("%s update user info password success, update num: %d", userInfo.UserId, num)
	}
}

func UpdateUserInfo(ctx context.Context, userInfo UserInfo) {
	o := orm.NewOrm()
	if num, err := o.UpdateWithCtx(ctx, &userInfo); err != nil {
		logs.Error("update user info fail: ", err)
	} else {
		logs.Info("update user info success, num: ", num)
	}
}

func UpdateStauts(ctx context.Context, status, userId string) bool {
	o := orm.NewOrm()
	_, err := o.QueryTable(USERINFO).Filter("user_id", userId).UpdateWithCtx(ctx, orm.Params{"status": status})

	if err != nil {
		logs.Error("update status fail: ", err)
		return false
	}
	return true
}

func UserInfoExistByUserId(ctx context.Context, userId string) bool {
	o := orm.NewOrm()
	exist := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("user_id", userId).ExistWithCtx(ctx)
	return exist
}

func NickIsExist(ctx context.Context, nick string) bool {
	o := orm.NewOrm()
	exist := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("nick", nick).ExistWithCtx(ctx)
	return exist
}

func InsertUser(ctx context.Context, userInfo UserInfo) bool {
	o := orm.NewOrm()
	_, err := o.InsertWithCtx(ctx, &userInfo)
	if err != nil {
		logs.Error("insert user fail: ", err)
		return false
	}
	return true
}

func DeleteUserByUserId(ctx context.Context, userId string) bool {
	o := orm.NewOrm()
	_, err := o.QueryTable(USERINFO).Exclude("status", "delete").Filter("user_id", userId).UpdateWithCtx(ctx, orm.Params{"status": "delete"})

	if err != nil {
		logs.Error("delete user by userId fail: ", err)
		return false
	}
	return true
}
