package service

import (
	"context"
	"errors"
	"github.com/jinzhu/gorm"
	"github.com/longjoy/micro-go-course/section11/user/dao"
	"github.com/longjoy/micro-go-course/section11/user/redis"
	"log"
	"time"
)

type UserInfoDTO struct {

	ID int64 `json:"id"`
	Username string `json:"username"`
	Email string `json:"email"`

}

type RegisterUserVO struct {
	Username string
	Password string
	Email string
}


var (
	ErrUserExisted = errors.New("user is existed")
	ErrPassword = errors.New("email and password are not match")
	ErrRegistering = errors.New("email is registering")
)

type UserService interface {
	// 登录接口
	Login(ctx context.Context, email, password string)(*UserInfoDTO, error)
	// 注册接口
	Register(ctx context.Context, vo *RegisterUserVO)(*UserInfoDTO, error)
}

type UserServiceImpl struct {
	userDAO dao.UserDAO
}

func MakeUserServiceImpl(userDAO dao.UserDAO) UserService {
	return &UserServiceImpl{
		userDAO:userDAO,
	}
}

func (userService *UserServiceImpl) Login(ctx context.Context, email, password string)(*UserInfoDTO, error)  {

	user, err := userService.userDAO.SelectByEmail(email); if err == nil{
		if user.Password == password{
			return &UserInfoDTO{
				ID:user.ID,
				Username:user.Username,
				Email:user.Email,
			}, nil
		}else {
			return nil, ErrPassword
		}
	}else {
		log.Printf("err : %s", err)
	}
	return nil, err
}

func (userService UserServiceImpl)  Register(ctx context.Context, vo *RegisterUserVO)(*UserInfoDTO, error){

	lock := redis.GetRedisLock(vo.Email, time.Duration(5) * time.Second)
	err := lock.Lock(); if err != nil{
		log.Printf("err : %s", err)
		return nil, ErrRegistering
	}
	defer lock.Unlock()

	existUser, err := userService.userDAO.SelectByEmail(vo.Email)

	if (err == nil && existUser == nil) || err == gorm.ErrRecordNotFound {
		newUser := &dao.UserEntity{
			Username:vo.Username,
			Password:vo.Password,
			Email:vo.Email,
		}
		err = userService.userDAO.Save(newUser);if err == nil{
			return &UserInfoDTO{
				ID:newUser.ID,
				Username:newUser.Username,
				Email:newUser.Email,
			}, nil
		}
	}
	if err == nil{
		err = ErrUserExisted
	}
	return nil, err

}