package filter

import (
	"errors"
	"fmt"
	"math/rand"
	"sort"
	"time"

	"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/recconf"
	psort "gitlab.alibaba-inc.com/pai_biz_arch/pairec/sort"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
)

const (
	Fix_Count_Type        = "fix"
	Accumulate_Count_Type = "accumulator"
)

type PriorityAdjustCountFilter struct {
	configs []recconf.AdjustCountConfig
}

func NewPriorityAdjustCountFilter(config recconf.FilterConfig) *PriorityAdjustCountFilter {
	filter := PriorityAdjustCountFilter{
		configs: config.AdjustCountConfs,
	}

	return &filter
}
func (f *PriorityAdjustCountFilter) Filter(filterData *FilterData) error {
	context := filterData.Context
	if context.ExperimentResult != nil {
		rankconf := context.ExperimentResult.GetExperimentParams().Get("generalRankConf", "")
		if rankconf != "" {
			return nil
		}
	}

	if _, ok := filterData.Data.([]*module.Item); !ok {
		return errors.New("filter data type error")

	}
	return f.doFilter(filterData)
}

func (f *PriorityAdjustCountFilter) doFilter(filterData *FilterData) error {
	start := time.Now()
	items := filterData.Data.([]*module.Item)
	newItems := make([]*module.Item, 0, 200)
	recallToItemMap := make(map[string][]*module.Item)

	// first random
	rand.Shuffle(len(items)/2, func(i, j int) {
		items[i], items[j] = items[j], items[i]
	})

	sort.Sort(sort.Reverse(psort.ItemScoreSlice(items)))

	for _, item := range items {
		recallToItemMap[item.RetrieveId] = append(recallToItemMap[item.RetrieveId], item)
	}

	accumulator := 0
	for _, config := range f.configs {
		recallItems := recallToItemMap[config.RecallName]
		if config.Type == Fix_Count_Type {
			if len(recallItems) < config.Count {
				newItems = append(newItems, recallItems...)
			} else {
				newItems = append(newItems, recallItems[:config.Count]...)
			}
		} else if config.Type == Accumulate_Count_Type {
			count := config.Count - accumulator
			if len(recallItems) >= count {
				newItems = append(newItems, recallItems[:count]...)
				accumulator += count
			} else {
				newItems = append(newItems, recallItems...)
				accumulator += len(recallItems)
			}
		}
	}

	filterData.Data = newItems
	log.Info(fmt.Sprintf("requestId=%s\tmodule=PriorityAdjustCountFilter\tlen=%d\tcost=%d", filterData.Context.RecommendId, len(newItems), utils.CostTime(start)))
	return nil
}
