package auth

import (
	"fmt"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/log"
	"strconv"
	"time"

	"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/im"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/infrastructure/pg/transaction"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/infrastructure/utils"
	"gitlab.fjmaimaimai.com/mmm-go/partner/pkg/protocol"
)

// 更新用户 IM INFO
func InitOrUpdateUserIMInfo(partnerInfo *domain.PartnerInfo, ctx *transaction.TransactionContext) (err error) {
	var (
		ImInfoRepository, _                          = factory.CreateImInfoRepository(ctx)
		checkImRequest      *protocol.CheckImRequest = &protocol.CheckImRequest{}
		IsCreated                                    = false
		checkImResponse     *protocol.CheckImResponse
	)
	imInfo, e := ImInfoRepository.FindOne(map[string]interface{}{"user_id": partnerInfo.Id})
	// 异常
	if e != nil && e != domain.QueryNoRow {
		err = e
		return
	}
	// 不存在
	if e == domain.QueryNoRow {
		imInfo = &domain.ImInfo{
			UserId:     partnerInfo.Id,
			CreateTime: time.Now(),
		}
	}
	// 已存在
	if e == nil && imInfo != nil {
		IsCreated = true
	}

	if len(imInfo.ImId) == 0 {
		id, _ := utils.NewSnowflakeId()
		imInfo.ImId = fmt.Sprintf("%v", id)
	}
	checkImRequest = &protocol.CheckImRequest{
		UserId:       imInfo.UserId,
		ImId:         imInfo.ImId,
		Uname:        partnerInfo.PartnerName,
		CustomerImId: fmt.Sprintf("%v", imInfo.CustomerImId),
		IsCreated:    IsCreated,
	}
	if checkImResponse, err = CheckIm(checkImRequest); err != nil {
		return
	}
	if imInfo.CustomerImId == 0 {
		imInfo.CustomerImId = getRandomCustomerAccount(partnerInfo.Id, ctx)
	}
	imInfo.ImToken = checkImResponse.ImToken
	imInfo.UpdateTime = time.Now()
	if _, err = ImInfoRepository.Save(imInfo); err != nil {
		return
	}
	return
}

// 检查ImToken
func CheckIm(request *protocol.CheckImRequest) (rsp *protocol.CheckImResponse, err error) {
	var ()
	rsp = &protocol.CheckImResponse{}
	if !request.IsCreated {
		if err = imCreate(request, rsp); err != nil {
			return
		}
	} else {
		if err = imUpdate(request, rsp); err != nil {
			return
		}
	}
	if err = imRefreshToken(request, rsp); err != nil {
		return
	}
	return
}

//create
func imCreate(request *protocol.CheckImRequest, rsp *protocol.CheckImResponse) (err error) {
	var (
		param im.UserCreate = im.UserCreate{
			Accid: request.ImId,
			Name:  request.Uname,
			Icon:  request.Icon,
		}
		out *im.UserTokenResult
	)
	if out, err = im.CallCreate(param); err != nil {
		return
	}
	if out.Code != 200 || (out.Info.Accid != request.ImId) {
		return im.ErrorFailCall
	}
	rsp.ImToken = out.Info.Token
	return
}

//update user info
func imUpdate(request *protocol.CheckImRequest, rsp *protocol.CheckImResponse) (err error) {
	var (
		param im.UserUpdate = im.UserUpdate{
			Accid: request.ImId,
			Name:  request.Uname,
			Icon:  request.Icon,
		}
		out *im.BaseResp
	)
	if out, err = im.CallUpdate(param); err != nil {
		return
	}
	if out.Code != 200 {
		return im.ErrorFailCall
	}
	return
}

//refresh token
func imRefreshToken(request *protocol.CheckImRequest, rsp *protocol.CheckImResponse) (err error) {
	var (
		param im.UserRefreshToken = im.UserRefreshToken{
			Accid: request.ImId,
		}
		out *im.UserTokenResult
	)
	if out, err = im.CallRefreshToken(param); err != nil {
		return
	}
	if out.Code != 200 || (out.Info.Accid != request.ImId) {
		return im.ErrorFailCall
	}
	rsp.ImToken = out.Info.Token
	return
}

// 获取客服id
func getRandomCustomerAccount(userId int64, ctx *transaction.TransactionContext) (acid int64) {
	CustomerServiceRepository, _ := factory.CreateCustomerServiceRepository(ctx)
	total, customers, err := CustomerServiceRepository.Find(map[string]interface{}{"sortById": domain.ASC})
	if err != nil {
		log.Error(err)
		return 0
	}
	if total == 0 {
		return 0
	}
	index := userId % total
	if int(index) < len(customers) {
		acid, _ = strconv.ParseInt(customers[index].ImId, 10, 64)
		return
	}
	acid, _ = strconv.ParseInt(customers[0].ImId, 10, 64)
	return
}