package auth

import (
	"encoding/json"
	"fmt"
	"github.com/GeeTeam/gt3-golang-sdk/geetest"
	"github.com/tiptok/gocomm/common"
	"github.com/tiptok/gocomm/pkg/cache"
	"github.com/tiptok/gocomm/pkg/log"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/cachex"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/factory"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/domain"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/infrastructure/dao"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/infrastructure/utils"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/protocol"
	protocolx "gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/protocol/auth"
	"time"
)

type AuthService struct {
}

func (svr *AuthService) Login(header *protocol.RequestHeader, request *protocolx.LoginRequest) (rsp *protocolx.LoginResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		UserRepository, _     = factory.CreateUserRepository(transactionContext)
	)
	rsp = &protocolx.LoginResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var user *domain.Users
	if user, err = UserRepository.FindOne(map[string]interface{}{"phone": request.UserName}); err != nil || user == nil {
		err = protocol.NewCustomMessage(1, "用户不存在!")
		return
	}
	if user.Passwd != request.Password {
		err = protocol.NewCustomMessage(1, "密码有误!")
		return
	}
	if user.Status != domain.StatusNormal {
		err = protocol.NewCustomMessage(1, "该账号已被禁用!")
		return
	}
	token, _ := common.GenerateToken(fmt.Sprintf("%v", user.Id), user.Passwd, common.WithExpire(domain.TokenExpire), common.WithAddData(map[string]interface{}{"UserName": user.Name}))
	rsp.Access = map[string]interface{}{
		"accessToken": token, //"Bearer " + token,
		"expiresIn":   domain.TokenExpire,
	}

	cache.Delete(cachex.UserRoleAccessCacheKey(user.Id))
	err = transactionContext.CommitTransaction()
	return
}

func (svr *AuthService) Logout(header *protocol.RequestHeader, request *protocolx.LogoutRequest) (rsp *protocolx.LogoutResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &protocolx.LogoutResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	err = transactionContext.CommitTransaction()
	return
}

func (svr *AuthService) Profile(header *protocol.RequestHeader, request *protocolx.ProfileRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		UserRepository, _     = factory.CreateUserRepository(transactionContext)
		RoleRepository, _     = factory.CreateRoleRepository(transactionContext)
		RoleAccessDao, _      = dao.NewRoleAccessDao(transactionContext)
		AccessRepository, _   = factory.CreateAccessRepository(transactionContext)
	)
	rsp = &protocolx.ProfileResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var user *domain.Users
	if user, err = UserRepository.FindOne(map[string]interface{}{"id": request.UserId}); err != nil {
		err = protocol.NewCustomMessage(1, "用户不存在")
		return
	}
	_, roles, _ := RoleRepository.Find(map[string]interface{}{"inRoleIds": user.Roles})

	rspMap := map[string]interface{}{
		"menus": struct{}{},
	}
	rspMap["user"] = map[string]interface{}{
		"name":      user.Name,
		"id":        user.Id,
		"phone":     user.Phone,
		"adminType": user.AdminType,
		"roles":     utils.LoadCustomField(roles, "Id", "RoleName"),
	}
	if user.AdminType == domain.UserAdmin {
		_, accesses, _ := AccessRepository.Find(map[string]interface{}{})
		rspMap["menus"] = accesses
	} else {
		accessIds, _ := RoleAccessDao.GetRoleAccess(user.Roles...)
		if len(accessIds) > 0 {
			_, accesses, _ := AccessRepository.Find(map[string]interface{}{"inAccessIds": accessIds})
			rspMap["menus"] = accesses
		}
	}
	rsp = rspMap
	err = transactionContext.CommitTransaction()
	return
}

func (svr *AuthService) CaptchaInit(header *protocol.RequestHeader, request *protocolx.CaptchaInitRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &protocolx.CaptchaInitResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	const (
		captchaID  = "33a2abf9c5df0d6bc3b89fb39280114b"
		privateKey = "13320fd2b10199e9a2440a4fbb4d46f7"
	)
	newGeetest := geetest.NewGeetestLib(captchaID, privateKey, 2*time.Second)
	_, responseBt := newGeetest.PreProcess("", request.UserIp)
	var geetestRsp geetest.FailbackRegisterRespnse
	json.Unmarshal(responseBt, &geetestRsp)
	rspData := map[string]interface{}{
		"success":    geetestRsp.Success,
		"gt":         geetestRsp.GT,
		"challenge":  geetestRsp.Challenge,
		"newCaptcha": geetestRsp.NewCaptcha,
	}
	rsp = rspData
	err = transactionContext.CommitTransaction()
	return
}

func (svr *AuthService) ChangePassword(header *protocol.RequestHeader, request *protocolx.ChangePasswordRequest) (rsp *protocolx.ChangePasswordResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		UserRepository, _     = factory.CreateUserRepository(transactionContext)
	)
	rsp = &protocolx.ChangePasswordResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var user *domain.Users
	if user, err = UserRepository.FindOne(map[string]interface{}{"phone": request.Phone}); err != nil {
		err = protocol.NewCustomMessage(1, "用户不存在")
		return
	}
	if user.Passwd != request.OldPwd {
		err = protocol.NewCustomMessage(1, "旧密码输入有误")
		return
	}
	user.Passwd = request.NewPwd
	if _, err = UserRepository.Save(user); err != nil {
		return
	}

	err = transactionContext.CommitTransaction()
	return
}

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