package auth

import (
	"fmt"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/application/factory"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/domain"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/infrastructure/domain_service"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/infrastructure/utils"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/log"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/protocol"
	protocolx "gitlab.fjmaimaimai.com/mmm-go/partner/pkg/protocol/auth"
	"strconv"
	"strings"
	"time"
)

func Login(header *protocol.RequestHeader, request *protocol.LoginRequest) (rsp *protocol.LoginResponse, err error) {
	var (
		transactionContext, _          = factory.CreateTransactionContext(nil)
		PartnerInfoService, _          = factory.CreatePartnerInfoRepositoryIn(transactionContext)
		partnerInfo                    *domain.PartnerInfo
		result                         bool = false
		PartnerSubAccountRepository, _      = factory.CreatePartnerSubAccountRepository(transactionContext)
		partnerSubAccount              *domain.PartnerSubAccount
	)
	if err = transactionContext.StartTransaction(); err != nil {
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	rsp = &protocol.LoginResponse{}
	if partnerSubAccount, err = PartnerSubAccountRepository.FindOne(map[string]interface{}{"account": request.Phone}); err == nil {
		if partnerInfo, err = PartnerInfoService.FindOne(map[string]interface{}{"id": partnerSubAccount.PartnerId}); err != nil {
			//子账号
			err = protocol.NewErrWithMessage(502, err) //账号不存在
			return
		}
		partnerInfo.Password = partnerSubAccount.Password
	} else {
		if partnerInfo, err = PartnerInfoService.FindOne(map[string]interface{}{"account": request.Phone}); err != nil {
			//子账号
			err = protocol.NewErrWithMessage(502, err) //账号不存在
			return

		}
	}
	if !partnerInfo.IsEnable() {
		err = protocol.NewErrWithMessage(2002) //账号禁用
		return
	}
	switch request.GrantType {
	case protocol.LoginByPassword:
		if len(partnerInfo.Password) == 0 {
			err = protocol.NewCustomMessage(1, "密码不能为空!")
			return
		}
		if result = strings.EqualFold(partnerInfo.Password, request.Password); !result {
			err = protocol.NewCustomMessage(1, "密码输入有误!")
			return
		}
		break
	case protocol.LoginBySmsCode:
		if _, err = CheckSmsCode(request.Phone, request.Captcha); err != nil {
			return
		}
		break
	default:
		err = protocol.NewCustomMessage(1, "登录方式不支持!")
		break
	}
	rsp.AuthCode, _ = utils.GenerateToken(partnerInfo.Id, request.Phone, protocol.AuthCodeExpire*time.Second)

	if _, err = InitOrUpdateUserIMInfo(partnerInfo.Id, partnerInfo.PartnerName, transactionContext); err != nil {
		log.Error(err)
		return
	}
	err = transactionContext.CommitTransaction()
	return
}

func SmsCode(request *protocol.SmsCodeRequest) (rsp *protocol.SmsCodeResponse, err error) {
	var data map[string]interface{}
	sms, _ := factory.CreateSmsCodeService()
	data, err = sms.SendSms(request.Phone)
	rsp = &protocol.SmsCodeResponse{}
	if err != nil {
		if msg, ok := data["msg"]; ok {
			err = protocol.NewCustomMessage(1, msg.(string))
		}
		log.Error(err, data, request.Phone)
		return
	}
	err = protocol.NewSuccessWithMessage("发送验证码成功")
	return
}

func AccessToken(request *protocol.AccessTokenRequest) (rsp *protocol.AccessTokenResponse, err error) {
	var (
		claim *utils.UserTokenClaims
	)
	rsp = &protocol.AccessTokenResponse{}
	if claim, err = utils.ParseJWTToken(request.AuthCode); err != nil {
		err = protocol.NewErrWithMessage(4139, err)
		return
	}
	if claim.UserId <= 0 {
		err = protocol.NewErrWithMessage(1, fmt.Errorf("jwt authCode (%v) valid", request.AuthCode))
		return
	}
	rsp.AccessToken, _ = utils.GenerateToken(claim.UserId, claim.Phone, protocol.TokenExpire*time.Second)
	rsp.RefreshToken, _ = utils.GenerateToken(claim.UserId, claim.Phone, protocol.RefreshTokenExipre*time.Second)
	rsp.ExpiresIn = protocol.TokenExpire

	//auth := userAuth.NewRedisUserAuth(userAuth.WithUserId(claim.UserId),
	//	userAuth.WithAccessToken(rsp.AccessToken),
	//	userAuth.WithRefreshToken(rsp.RefreshToken))
	//if err = auth.AddAuth(); err != nil {
	//	log.Error(err)
	//	return
	//}
	return
}

func RefreshToken(request *protocol.RefreshTokenRequest) (rsp *protocol.RefreshTokenResponse, err error) {
	var (
		claim                          *utils.UserTokenClaims
		transactionContext, _          = factory.CreateTransactionContext(nil)
		PartnerInfoService, _          = factory.CreatePartnerInfoRepositoryIn(transactionContext)
		PartnerSubAccountRepository, _ = factory.CreatePartnerSubAccountRepository(transactionContext)

		partnerInfo       *domain.PartnerInfo
		partnerSubAccount *domain.PartnerSubAccount
	)

	if err = transactionContext.StartTransaction(); err != nil {
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	rsp = &protocol.RefreshTokenResponse{}
	if claim, err = utils.ParseJWTToken(request.RefreshToken); err != nil {
		err = protocol.NewErrWithMessage(4140, err)
		return
	}
	if claim.UserId <= 0 {
		err = protocol.NewErrWithMessage(1, fmt.Errorf("jwt refrshToken (%v) valid", request.RefreshToken))
		return
	}

	//验证用户有效
	var e error
	if partnerSubAccount, e = PartnerSubAccountRepository.FindOne(map[string]interface{}{"account": claim.Phone}); e == nil {
		partnerInfo, e = PartnerInfoService.FindOne(map[string]interface{}{"id": partnerSubAccount.PartnerId})
	} else {
		partnerInfo, e = PartnerInfoService.FindOne(map[string]interface{}{"account": claim.Phone})
	}
	if e != nil || partnerInfo == nil || !partnerInfo.IsEnable() || partnerInfo.Id != claim.UserId {
		err = protocol.NewErrWithMessage(4140) //账号禁用
		return
	}

	//oldAuth := userAuth.NewRedisUserAuth(userAuth.WithUserId(claim.UserId))
	//if err = oldAuth.Check(userAuth.NewOptions(userAuth.WithRefreshToken(request.RefreshToken))); err != nil {
	//	log.Error(err)
	//	err = protocol.NewErrWithMessage(4140, err)
	//	return
	//}
	rsp.AccessToken, _ = utils.GenerateToken(claim.UserId, claim.Phone, protocol.TokenExpire*time.Second)
	rsp.RefreshToken, _ = utils.GenerateToken(claim.UserId, claim.Phone, protocol.RefreshTokenExipre*time.Second)
	rsp.ExpiresIn = protocol.TokenExpire

	//newAuth := userAuth.NewRedisUserAuth(userAuth.WithUserId(claim.UserId),
	//	userAuth.WithAccessToken(rsp.AccessToken),
	//	userAuth.WithRefreshToken(rsp.RefreshToken))
	//if err = newAuth.AddAuth(); err != nil {
	//	log.Error(err)
	//	return
	//}
	err = transactionContext.CommitTransaction()
	return
}

//验证短信验证码 T
func CheckSmsCode(phone, code string) (result bool, err error) {
	sms, _ := factory.CreateSmsCodeService()
	var data map[string]interface{}
	data, err = sms.CheckSmsCode(phone, code)
	if err != nil {
		if msg, ok := data["msg"]; ok {
			err = protocol.NewCustomMessage(1, msg.(string))
		}
		return
	}
	return
}

//验证手机号码(修改手机号码、重置密码的前一步)
func AuthCheckSmsCode(header *protocol.RequestHeader, request *protocol.AuthCheckSmsCodeRequest) (rsp *protocol.AuthCheckSmsCodeResponse, err error) {
	var ()
	if _, err = CheckSmsCode(request.Phone, request.Captcha); err != nil {
		return
	}
	rsp = &protocol.AuthCheckSmsCodeResponse{
		CaptchaCertificate: fmt.Sprintf("%v", utils.GenerateRangeNum(100000, 799999)),
	}
	return
}

//注销登录
func Revoke(header *protocol.RequestHeader, request *protocol.RevokeRequest) (rsp *protocol.RevokeResponse, err error) {
	//auth := userAuth.NewRedisUserAuth(userAuth.WithUserId(header.UserId))
	//rsp = &protocol.RevokeResponse{}
	//if !auth.Exist() {
	//	return
	//}
	//if err = auth.RemoveAuth(); err != nil {
	//	log.Error(err)
	//	err = protocol.NewErrWithMessage(4140, err)
	//	return
	//}
	return
}

func CenterCompanys(header *protocol.RequestHeader, request *protocolx.CenterCompanysRequest) (rsp *protocolx.CenterCompanysResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		imInfo                *domain.ImInfo
		loginSvr              = domain_service.NewPgLoginService(transactionContext)
	)
	phoneId, e := strconv.Atoi(request.Phone)
	if e != nil {
		log.Error(e)
		e = protocol.NewErrWithMessage(2)
		return
	}
	rsp = &protocolx.CenterCompanysResponse{}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	loginSvr.Init(request.Phone)
	if len(loginSvr.Users) == 0 && len(loginSvr.PartnerInfo) == 0 {
		err = protocol.NewErrWithMessage(502, err) //账号不存在
		return
	}
	switch request.GrantType {
	case protocol.LoginByPassword:
		if loginSvr.ManagerLogin(request.Phone, request.Password) != nil && loginSvr.PartnerLogin(request.Phone, request.Password) != nil {
			err = protocol.NewCustomMessage(1, "密码输入有误!")
			return
		}
		break
	case protocol.LoginBySmsCode:
		if _, err = CheckSmsCode(request.Phone, request.Captcha); err != nil {
			return
		}
		break
	default:
		err = protocol.NewCustomMessage(1, "登录方式不支持!")
		break
	}

	//获取统计信息
	rsp.Partner, _ = loginSvr.PartnerStaticInfo()
	rsp.Manager, _ = loginSvr.ManagerStaticInfo()
	//没有有效人的时候
	//if rsp.Partner ==nil && rsp.Manager ==nil{
	//	err = protocol.NewErrWithMessage(2002) //账号禁用
	//	return
	//}

	var nickName string
	if len(loginSvr.Users) > 0 {
		nickName = loginSvr.Users[0].Name
	} else if len(loginSvr.PartnerInfo) > 0 {
		nickName = loginSvr.PartnerInfo[0].PartnerName
	}
	//初始化im信息
	if imInfo, err = InitOrUpdateUserIMInfo(int64(phoneId), nickName, transactionContext); err != nil {
		log.Error(err)
		return
	}

	rsp.CsAccountID = fmt.Sprintf("%v", imInfo.CustomerImId)
	rsp.ImToken = imInfo.ImToken
	rsp.Accid, _ = strconv.Atoi(imInfo.ImId)
	rsp.Credentials, _ = utils.GenerateToken(int64(phoneId), request.Phone, protocol.RefreshTokenExipre*time.Second)

	err = transactionContext.CommitTransaction()
	return
}

func Companys(header *protocol.RequestHeader, request *protocolx.CompanysRequest) (rsp *protocolx.CompanysResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		loginSvr              = domain_service.NewPgLoginService(transactionContext)
		claim                 *utils.UserTokenClaims
	)
	rsp = &protocolx.CompanysResponse{}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if claim, err = utils.ParseJWTToken(request.Credentials); err != nil {
		err = protocol.NewErrWithMessage(4139, err)
		return
	}
	loginSvr.Init(claim.Phone)
	rsp.Partner, _ = loginSvr.PartnerStaticInfo()
	rsp.Manager, _ = loginSvr.ManagerStaticInfo()
	err = transactionContext.CommitTransaction()
	return
}

func LoginV2(header *protocol.RequestHeader, request *protocol.LoginRequestV2) (rsp *protocol.LoginResponse, err error) {
	var (
		claim                    *utils.UserTokenClaims
		transactionContext, _    = factory.CreateTransactionContext(nil)
		PartnerInfoRepository, _ = factory.CreatePartnerInfoRepositoryIn(transactionContext)
		UsersRepository, _       = factory.CreateUsersRepository(transactionContext)
		userId                   int64
	)
	rsp = &protocol.LoginResponse{}
	if err = transactionContext.StartTransaction(); err != nil {
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	if claim, err = utils.ParseJWTToken(request.Credentials); err != nil {
		err = protocol.NewErrWithMessage(4140, err)
		return
	}
	switch request.IdType {
	case int(protocolx.AdminTypePartner):
		if p, e := PartnerInfoRepository.FindOne(map[string]interface{}{"account": claim.Phone, "company_id": request.Cid, "status": 1}); e == nil {
			userId = p.Id
		}
		break
	case int(protocolx.AdminTypeManager):
		if p, e := UsersRepository.FindOne(map[string]interface{}{"phone": claim.Phone, "company_id": request.Cid, "status": 1}); e == nil {
			userId = p.Id
		}
		break
	default:
		err = protocol.NewErrWithMessage(2, fmt.Errorf("idType :%v not in range (1,2)", request.IdType)) //用户类型有误
		return
	}
	if userId == 0 {
		err = protocol.NewErrWithMessage(502, err) //账号不存在
		return
	}
	//根据simnum + cid
	rsp.AuthCode, _ = utils.GenerateTokenWithAdminType(userId, claim.Phone, request.IdType, protocol.AuthCodeExpire*time.Second)

	err = transactionContext.CommitTransaction()
	return
}