package service

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/auth/command"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/auth/query"
	"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"
	"time"
)

type AuthService struct {
}

func (svr *AuthService) Login(header *protocol.RequestHeader, request *command.LoginRequest) (rsp *command.LoginResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		UserRepository, _     = factory.CreateUserRepository(transactionContext)
	)
	rsp = &command.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, "Phone": user.Phone}))
	refreshToken, _ := common.GenerateToken(fmt.Sprintf("%v", user.Id), user.Passwd, common.WithExpire(domain.RefreshTokenExpire), common.WithAddData(map[string]interface{}{"UserName": user.Name, "Phone": user.Phone}))
	rsp.Access = map[string]interface{}{
		"accessToken":  token,
		"refreshToken": refreshToken,
		"expiresIn":    domain.TokenExpire,
	}

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

func (svr *AuthService) Logout(header *protocol.RequestHeader, request *command.LogoutRequest) (rsp *command.LogoutResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &command.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) Refresh(header *protocol.RequestHeader, request *command.RefreshRequest) (rsp interface{}, err error) {
	var (
	//transactionContext, _          = factory.CreateTransactionContext(nil)
	)
	//transactionContext.SetTransactionClose()
	rsp = &command.RefreshResponse{}
	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()
	//}()

	claim, e := common.ParseJWTToken(request.RefreshToken)
	if e != nil {
		log.Error(e)
		err = protocol.NewCustomMessage(-2, "权限过期,请重新登录")
		return
	}
	log.Debug(claim.Username, claim.Password, time.Unix(claim.ExpiresAt, 0))
	rsp, err = svr.Login(header, &command.LoginRequest{UserName: (claim.AddData["Phone"]).(string), Password: claim.Password})

	//err = transactionContext.CommitTransaction()
	return
}

func (svr *AuthService) Profile(header *protocol.RequestHeader, request *command.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 = &command.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((domain.Roles(roles)).RoleIds()...)
		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 *query.CaptchaInitRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &query.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 *command.ChangePasswordRequest) (rsp *command.ChangePasswordResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		UserRepository, _     = factory.CreateUserRepository(transactionContext)
	)
	rsp = &command.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()
	}()

	if claim, e := common.ParseJWTToken(header.Token); e == nil && len(request.Phone) == 0 {
		request.Phone = claim.AddData["Phone"].(string)
	}

	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.Password
	if _, err = UserRepository.Save(user); err != nil {
		return
	}

	err = transactionContext.CommitTransaction()
	return
}

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