package service

import (
	"crypto/sha1"
	"fmt"
	"io"
	"iot_manager_service/app/system/dao"
	"iot_manager_service/app/system/model"
	"iot_manager_service/config"
	"iot_manager_service/util/cache"
	"iot_manager_service/util/common"
	"iot_manager_service/util/logger"
	"iot_manager_service/util/minio"
	"mime/multipart"
	"strings"
	"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 string) *dao.User {
	user := &dao.User{
		TenantId: tenantId,
	}
	err := user.GetUserByTenantId()
	if err != nil {
		return nil
	}
	return user
}

func (s *userService) GetOne(tenantId string, 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 string, 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()
}

// UpAvatar  上传头像
func (s *userService) UpAvatar(tenantId string, userId int64, fileHeader *multipart.FileHeader) *model.Link {
	//检查是否已有头像,成功上传后将其删除
	dao := &dao.User{TenantId: tenantId, ID: userId}
	dao.GetAvatar()
	oldAvatar := dao.Avatar

	file, err := fileHeader.Open()
	//文件校验
	if err != nil {
		logger.Logger.Errorf("UploadFile fileHeader.Open fail, err = %s", err.Error())
		return nil
	}
	fileNameArray := strings.Split(fileHeader.Filename, ".")
	if len(fileNameArray) < 2 {
		return nil
	}
	//上传
	bucket := fmt.Sprintf("picture-%d", tenantId)
	objectName := "user/" + common.RandomString2(16) + "_" + common.RandomString2(6) + "." + fileNameArray[len(fileNameArray)-1]
	err = minio.PutFile(minio.FileObject{
		Bucket:     bucket,
		ObjectName: objectName,
		ObjectSize: fileHeader.Size,
		Reader:     file,
	})
	if err != nil {
		logger.Logger.Errorf("UploadFile PutFile fail, err = %s", err.Error())
		return nil
	}
	//从minio删除旧的
	if oldAvatar != "" {
		old := strings.Split(oldAvatar, "user/")
		oldName := "user/" + old[1]
		minio.DeleteObject(bucket, oldName)
	}
	//新的保存到数据库
	url := config.Instance().Minio.Link + "/" + bucket + "/" + objectName
	dao.Avatar = url
	dao.Update()
	fmt.Printf("\n=====user:%+v\n", dao)
	var link = model.Link{Link: url}
	return &link
}
