package recall

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/persist/cache"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
)

type Recall interface {
	GetCandidateItems(user *module.User, context *context.RecommendContext) []*module.Item
}

var recalls = make(map[string]Recall)

func RegisterRecall(name string, recall Recall) {
	recalls[name] = recall
}
func GetRecall(name string) (Recall, error) {
	recall, ok := recalls[name]
	if !ok {
		return nil, fmt.Errorf("Recall:not found, recall name:%s", name)
	}

	if recall == nil {
		return nil, fmt.Errorf("recall is nil, recall name:%s", name)
	}

	return recall, nil
}
func Load(config *recconf.RecommendConfig) {
	for _, conf := range config.RecallConfs {
		var recall Recall
		if conf.RecallType == "UserCollaborativeFilterRecall" {
			recall = NewUserCollaborativeFilterRecall(conf)
		} else if conf.RecallType == "UserTopicRecall" {
			recall = NewUserTopicRecall(conf)
		} else if conf.RecallType == "VectorRecall" {
			recall = NewVectorRecall(conf)
		} else if conf.RecallType == "UserCustomRecall" {
			recall = NewUserCustomRecall(conf)
		} else if conf.RecallType == "HologresVectorRecall" {
			recall = NewHologresVectorRecall(conf)
		} else if conf.RecallType == "ItemCollaborativeFilterRecall" {
			recall = NewItemCollaborativeFilterRecall(conf)
		} else if conf.RecallType == "UserGroupHotRecall" {
			recall = NewUserGroupHotRecall(conf)
		} else if conf.RecallType == "UserGlobalHotRecall" {
			recall = NewUserGlobalHotRecall(conf)
		} else if conf.RecallType == "I2IVectorRecall" {
			recall = NewI2IVectorRecall(conf)
		} else if conf.RecallType == "ColdStartRecall" {
			recall = NewColdStartRecall(conf)
		}

		if recall == nil {
			panic(fmt.Sprintf("recall empty, name:%s", conf.Name))
		}

		RegisterRecall(conf.Name, recall)
	}

}

type BaseRecall struct {
	modelName   string
	cache       cache.Cache
	cachePrefix string
	cacheTime   int
	itemType    string
	recallCount int
	recallAlgo  string
}

func NewBaseRecall(config recconf.RecallConfig) *BaseRecall {
	recall := &BaseRecall{
		modelName:   config.Name,
		itemType:    config.ItemType,
		recallCount: config.RecallCount,
		recallAlgo:  config.RecallAlgo,
	}
	if len(config.CacheAdapter) > 0 {
		cache, err := cache.NewCache(config.CacheAdapter,
			config.CacheConfig)
		if err != nil {
			log.Error(fmt.Sprintf("error=%v", err))
		} else {
			recall.cache = cache
			recall.cachePrefix = config.CachePrefix
			recall.cacheTime = config.CacheTime
		}
	}

	return recall
}
