package service

import (
	"crypto/sha1"
	"fmt"
	"io"
	"iot_manager_service/app/system/dao"
	"iot_manager_service/app/system/model"
	"iot_manager_service/util/cache"
	"iot_manager_service/util/common"
	"iot_manager_service/util/logger"
	"time"
)

// 用户管理服务
var UserService = new(userService)

type userService struct{}

func (s *userService) Get(id int64) (*model.UserDetail, error) {
	user := &dao.User{
		ID: id,
	}
	err := user.GetUser()
	if err != nil {
		return nil, err
	}
	detail := &model.UserDetail{
		User:       *user,
		TenantName: TenantService.GetTenantName(user.TenantId, user.TenantId),
		RoleName:   RoleService.GetRoleName(user.TenantId, user.RoleId),
		SexName:    DictService.GetSexName(user.TenantId, user.Sex),
	}
	return detail, nil
}

func (s *userService) GetOneByTenantId(tenantId int) *dao.User {
	user := &dao.User{
		TenantId: tenantId,
	}
	err := user.GetUserByTenantId()
	if err != nil {
		return nil
	}
	return user
}

func (s *userService) GetOne(tenantId int, account, password string) *dao.User {
	// 密码前端先MD5 后端再sha1加密
	t := sha1.New()
	_, _ = io.WriteString(t, password)
	password = fmt.Sprintf("%x", t.Sum(nil))
	user := &dao.User{
		TenantId: tenantId,
		Account:  account,
		Password: password,
	}
	err := user.GetUserByPwd()
	if err != nil {
		return nil
	}
	return user
}

func (s *userService) List(account, realName string, current, size int) ([]model.UserDetail, int64, *common.Errors) {
	user := dao.User{}
	offset := (current - 1) * size
	limit := size
	if account != "" {
		user.Account = account
	}
	if realName != "" {
		user.RealName = realName
	}

	users, counts, err := user.GetUsers(offset, limit)
	if err != nil {
		return nil, 0, common.FailResponse(err.Error(), nil)
	}
	var details []model.UserDetail
	for _, user := range users {
		details = append(details, model.UserDetail{
			User:       user,
			TenantName: TenantService.GetTenantName(user.TenantId, user.TenantId),
			RoleName:   RoleService.GetRoleName(user.TenantId, user.RoleId),
			SexName:    DictService.GetSexName(user.TenantId, user.Sex),
		})
	}
	return details, counts, nil
}

func (s *userService) Info(userInfo *dao.User) *common.Errors {

	err := userInfo.GetUser()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return nil
}

// Submit Birthday为""时在数据库报错,给一个默认值.
func (s *userService) Submit(req dao.User) *common.Errors {
	user := &req
	if user.Birthday == "" {
		user.Birthday = "1900-01-01 00:00:00"
	}
	err := user.Save()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return nil
}

func (s *userService) Update(req dao.User) *common.Errors {
	user := &req
	if user.Birthday == "" {
		user.Birthday = "1900-01-01 00:00:00"
	}
	err := user.Update()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return nil
}

func (s *userService) Remove(userId, id int64) *common.Errors {
	user := &dao.User{
		ID:         id,
		IsDeleted:  1,
		UpdateUser: userId,
		UpdateTime: time.Now(),
	}
	err := user.Remove()
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return nil
}

func (s *userService) ResetPwd(id int64) *common.Errors {
	user := &dao.User{ID: id}
	err := user.UpdatePwd(model.DefaultPwd)
	if err != nil {
		return common.FailResponse(err.Error(), nil)
	}
	return nil
}

func (s *userService) GetList() ([]dao.User, error) {
	user := &dao.User{}
	users, err := user.GetAll()
	if err != nil {
		return nil, err
	}
	return users, nil
}

func (s *userService) Grant(userIds []string, roleIds string) error {
	user := &dao.User{}
	return user.UpdateRoles(userIds, roleIds)
}

const UserKey = "%d:sys:user:%d"

func (s *userService) GetUserName(tenantId int, id int64) string {
	var name string
	key := fmt.Sprintf(UserKey, tenantId, id)
	name, err := cache.Redis.Get(key).Result()
	if err != nil {
		user := &dao.User{ID: id}
		if err := user.GetUser(); err != nil {
			logger.Logger.Errorf("GetUser err = %s \n", err)
		} else {
			name = user.Name
			cache.Redis.Set(key, name, time.Second*10)
		}
	}
	return name
}

func (s *userService) IsExist(user dao.User) bool {
	return user.IsExist()
}