package service

import (
	"fmt"

	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/module"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/hook"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/rank"
)

type UserRecommendService struct {
	RecommendService
	recallService  *RecallService
	rankService    *rank.RankService
	featureService *FeatureService
}

func NewUserRecommendService() *UserRecommendService {
	service := UserRecommendService{
		recallService:  &RecallService{},
		rankService:    rank.DefaultRankService(),
		featureService: DefaultFeatureService(),
	}
	return &service
}
func (r *UserRecommendService) Recommend(context *context.RecommendContext) []*module.Item {
	userId := r.GetUID(context)
	user := module.NewUserWithContext(userId, context)

	items := r.recallService.GetItems(user, context)

	// filter
	items = r.Filter(userId, items, context)

	size := context.Size

	if len(items) < size {
		scene := context.GetParameter("scene").(string)
		category := context.GetParameter("category").(string)
		alwaysRank := false
		if configs, ok := context.Config.SceneConfs[scene]; ok {
			if config, ok := configs[category]; ok {
				alwaysRank = config.AlwaysRank
			}

		}
		if alwaysRank == false {
			log.Info(fmt.Sprintf("requestId=%s\tmodule=recommend\tevent=filter\tuid=%s\tmsg=length of items less than size\tcount=%d", context.RecommendId, userId, len(items)))
			return items
		}
	}

	// pre rank
	preRank := GetGeneralRank(context)
	if preRank != nil {
		items = preRank.Rank(user, items, context)
	}

	// load user or item features
	// can load data from datasource(holo, ots, redis)
	// after load data, use feature engine to create or modify features
	items = r.featureService.LoadFeatures(user, items, context)

	r.rankService.Rank(user, items, context)
	// sort items
	items = r.Sort(items, context)

	if size > len(items) {
		size = len(items)
	}

	items = items[:size]

	// asynchronous clean hook func
	for _, hf := range hook.RecommendCleanHooks {
		go hf(context, user, items)
	}
	return items
}
