package service

import (
	"github.com/linmadan/egglib-go/core/application"
	"gitlab.fjmaimaimai.com/mmm-go-pp/partner01/pkg/application/auth/command"
	"gitlab.fjmaimaimai.com/mmm-go-pp/partner01/pkg/application/auth/query"
	"gitlab.fjmaimaimai.com/mmm-go-pp/partner01/pkg/application/factory"
	"gitlab.fjmaimaimai.com/mmm-go-pp/partner01/pkg/domain"
	"math/rand"
	"strconv"
	"strings"
)

// 认证服务
type AuthService struct {
}

// 用户按公司登录
func (authService *AuthService) AccessToken(accessTokenCommand *command.AccessTokenCommand) (interface{}, error) {
	if err := accessTokenCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	var claim = &domain.UserTokenClaim{}
	var result bool
	if result, err = domain.ValidToken(accessTokenCommand.AuthCode, claim); err != nil || !result {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	userId := claim.UserId
	companyId := claim.CompanyId
	rspMapData := map[string]interface{}{
		"accessToken":  domain.SignToken(int64(userId), companyId),
		"refreshToken": domain.SignToken(int64(userId), companyId),
	}
	return rspMapData, nil
}

// 修改手机号密码
func (authService *AuthService) ChangePassword(changePasswordCommand *command.ChangePasswordCommand) (interface{}, error) {
	if err := changePasswordCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	var (
		userAuth *domain.UserAuth
	)
	UserAuthRepository, _ := factory.CreateUserAuthRepository(map[string]interface{}{"transactionContext": transactionContext})
	userAuth, err = UserAuthRepository.FindOne(map[string]interface{}{"phone": changePasswordCommand.Phone})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if !strings.EqualFold(userAuth.PhoneAuth.Password, changePasswordCommand.OldPwd) {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "密码有误!")
	}
	if err = userAuth.Update(map[string]interface{}{"password": changePasswordCommand.NewPwd}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if _, err = UserAuthRepository.Save(userAuth); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return nil, nil
}

// 用户登录 返回有权限的公司列表
func (authService *AuthService) Login(loginQuery *query.LoginQuery) (interface{}, error) {
	if err := loginQuery.ValidateQuery(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var (
		userAuth      *domain.UserAuth
		users         []*domain.User
		rspMapData    = make(map[string]interface{})
		userCompanies []interface{}
	)
	UserAuthRepository, _ := factory.CreateUserAuthRepository(map[string]interface{}{"transactionContext": transactionContext})
	UserRepository, _ := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext})
	switch loginQuery.GrantType {
	case "signInPassword":
		if len(loginQuery.Password) == 0 {
			return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "密码不能为空!")
		}
		userAuth, err = UserAuthRepository.FindOne(map[string]interface{}{"phone": loginQuery.Phone})
		if err != nil {
			return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
		}
		if !strings.EqualFold(userAuth.PhoneAuth.Password, loginQuery.Password) {
			return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "密码有误!")
		}
	case "signInCaptcha":
	case "signInCredentials":
	default:
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "undefined grantType:"+loginQuery.GrantType)
	}
	_, users, err = UserRepository.Find(map[string]interface{}{"inUserIds": userAuth.Users, "status": domain.StatusEnable})

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	credentials := "cred:" + strconv.Itoa(rand.Int())
	rspMapData["credentials"] = credentials
	CompanyRepository, _ := factory.CreateCompanyRepository(map[string]interface{}{"transactionContext": transactionContext})
	for i := range users {
		company, _ := CompanyRepository.FindOne(map[string]interface{}{"companyId": users[i].CompanyId, "status": domain.StatusEnable})
		if company == nil {
			continue
		}
		item := map[string]interface{}{
			"user":    users[i],
			"company": company,
		}
		userCompanies = append(userCompanies, item)
	}
	return map[string]interface{}{"userCompanies": userCompanies, "credentials": credentials}, nil
}

// 用户按公司登录
func (authService *AuthService) LoginByCompany(loginByCompanyCommand *command.LoginByCompanyCommand) (interface{}, error) {
	if err := loginByCompanyCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	//todo:valid/refresh credentials
	if len(loginByCompanyCommand.Credentials) == 0 {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "credentials expire")
	}

	var user *domain.User
	UserRepository, _ := factory.CreateUserRepository(map[string]interface{}{"transactionContext": transactionContext})
	user, err = UserRepository.FindOne(map[string]interface{}{"userId": loginByCompanyCommand.UserId, "userType": loginByCompanyCommand.UserType})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	CompanyRepository, _ := factory.CreateCompanyRepository(map[string]interface{}{"transactionContext": transactionContext})
	company, err := CompanyRepository.FindOne(map[string]interface{}{"companyId": user.CompanyId, "status": domain.StatusEnable})
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	authCode := domain.SignToken(user.UserId, company.CompanyId)
	return map[string]interface{}{"user": user, "company": company, "authCode": authCode}, nil
}

// 更新授权令牌accessToken
func (authService *AuthService) RefreshToken(refreshTokenCommand *command.RefreshTokenCommand) (interface{}, error) {
	if err := refreshTokenCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	var claim = &domain.UserTokenClaim{}
	var result bool
	if result, err = domain.ValidToken(refreshTokenCommand.RefreshToken, claim); err != nil || !result {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	userId := claim.UserId
	companyId := claim.CompanyId
	rspMapData := map[string]interface{}{
		"accessToken":  domain.SignToken(int64(userId), companyId),
		"refreshToken": domain.SignToken(int64(userId), companyId),
	}
	return rspMapData, nil
}

// 注销登录
func (authService *AuthService) Revoke(revokeCommand *command.RevokeCommand) (interface{}, error) {
	if err := revokeCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return nil, nil
}

// 发送验证码
func (authService *AuthService) SendSmsCode(sendSmsCodeCommand *command.SendSmsCodeCommand) (interface{}, error) {
	if err := sendSmsCodeCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return nil, nil
}

func NewAuthService(options map[string]interface{}) *AuthService {
	newAuthService := &AuthService{}
	return newAuthService
}