package models

import (
	"sync"
	"time"

	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
	Model
	Name     string `json:"name"`
	Password string `json:"password"`
	Nickname string `json:"nickname"`
	Avator   string `json:"avator"`
	Role     int32  `json:"role"`
	RoleName string `json:"role_name" sql:"-"`
	RoleId   string `json:"role_id" sql:"-"`
	Status   int32  `json:"status" gorm:"default:1"`    // 1: active, 0: inactive
	IsOnline int32  `json:"is_online" gorm:"default:0"` // 1: online, 0: offline
}

func CreateUser(name string, password string, avator string, nickname string) uint {
	user := &User{
		Name:     name,
		Password: password,
		Avator:   avator,
		Nickname: nickname,
	}
	user.UpdatedAt = time.Now()
	DB.Create(user)
	return user.ID
}

func UpdateUserIsOnline(name string, isOnline int32) {
	user := &User{
		IsOnline: isOnline,
	}
	user.UpdatedAt = time.Now()
	DB.Model(user).Where("name = ?", name).Update("IsOnline", isOnline)
}

func UpdateUser(name string, password string, avator string, nickname string) {
	user := &User{
		Avator:   avator,
		Nickname: nickname,
	}
	user.UpdatedAt = time.Now()
	if password != "" {
		user.Password = password
	}
	DB.Model(&User{}).Where("name = ?", name).Update(user)
}
func UpdateUserPass(name string, pass string) {
	user := &User{
		Password: pass,
	}
	user.UpdatedAt = time.Now()
	DB.Model(user).Where("name = ?", name).Update("Password", pass)
}
func UpdateUserStatus(name string, status int32) {
	user := &User{
		Status: status,
	}
	user.UpdatedAt = time.Now()
	DB.Model(user).Where("name = ?", name).Update("Status", status)
}
func UpdateUserAvator(name string, avator string) {
	user := &User{
		Avator: avator,
	}
	user.UpdatedAt = time.Now()
	DB.Model(user).Where("name = ?", name).Update("Avator", avator)
}
func FindUser(username string) User {
	var user User
	DB.Where("name = ?", username).First(&user)
	return user
}

var (
	lastAssignedId uint
	assignMutex    sync.Mutex
)

func FindIdleUser() User {
	assignMutex.Lock()
	defer assignMutex.Unlock()

	users := FindOnlineUser()
	if len(users) == 0 {
		users = GetAllUsers()
	}

	if len(users) == 0 {
		return User{}
	}

	targetIndex := 0
	if lastAssignedId > 0 {
		for i, user := range users {
			if user.ID == lastAssignedId {
				targetIndex = i + 1
				break
			}
		}
	}

	if targetIndex >= len(users) {
		targetIndex = 0
	}

	targetUser := users[targetIndex]
	lastAssignedId = targetUser.ID

	return targetUser
}

func GetAllUsers() []User {
	var users []User
	DB.Where("name != ? and `status` = 1", "admin").Order("is_online desc").Find(&users)
	return users
}

func FindOnlineUser() []User {
	var users []User
	DB.Where("name != ? and `status` = 1 and is_online = 1", "admin").Order("id desc").Find(&users)

	return users
}

func FindUserById(id interface{}) User {
	var user User
	DB.Select("user.*,role.name role_name,role.id role_id").Joins("join user_role on user.id=user_role.user_id").Joins("join role on user_role.role_id=role.id").Where("user.id = ?", id).First(&user)
	return user
}
func DeleteUserById(id string) {
	DB.Where("id = ?", id).Delete(User{})
}
func FindUsers(withoutUsername string) []User {
	var users []User
	if withoutUsername == "" {
		DB.Find(&users)
	} else {
		DB.Where("name != ?", withoutUsername).Find(&users)
	}
	return users
}
func FindUserRole(query interface{}, id interface{}) User {
	var user User
	DB.Select(query).Where("user.id = ?", id).Joins("join user_role on user.id=user_role.user_id").Joins("join role on user_role.role_id=role.id").First(&user)
	return user
}
