package com.tzld.piaoquan.recommend.server.service.recall.strategy;

import com.tzld.piaoquan.recommend.server.model.Video;
import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class HeadCate1STRRecallStrategy implements RecallStrategy {
    private final String CLASS_NAME = this.getClass().getSimpleName();
    @Autowired
    private FilterService filterService;
    @Autowired
    @Qualifier("redisTemplate")
    public RedisTemplate<String, String> redisTemplate;

    public static final String PUSH_FORM = "recall_strategy_head_cate1_str";
    public static final String redisKeyPrefix = "merge_cate_str_recall:cate1";

    @Override
    public String pushFrom() {
        return PUSH_FORM;
    }

    @Override
    public List<Video> recall(RecallParam param) {
        List<Video> videosResult = new ArrayList<>();
        try {
            if (null == param.getVideoId() || 0 == param.getVideoId()) {
                return videosResult;
            }
            Long headVid = param.getVideoId();
            Map<String, String> headVideoInfo = param.getHeadInfo();
            if (null != headVideoInfo) {
                String cate = headVideoInfo.getOrDefault("merge_first_level_cate", "").trim();
                if (!cate.isEmpty() && !"unknown".equals(cate)) {
                    String key = String.format("%s:%s", redisKeyPrefix, cate);
                    String value = redisTemplate.opsForValue().get(key);
                    if (null == value || value.isEmpty()) {
                        return videosResult;
                    }
                    List<Long> vidList = parseVidList(headVid, value);
                    fillVideoResult(param, vidList, videosResult);
                }
            }
        } catch (Exception e) {
            log.error("recall is wrong in {}, error={}", CLASS_NAME, e);
        }
        return videosResult;
    }

    private List<Long> parseVidList(Long headVid, String data) {
        List<Long> vidList = new ArrayList<>();
        if (null != data && !data.isEmpty()) {
            String[] pair = data.split("\t");
            if (2 == pair.length) {
                Set<Long> hit = new HashSet<>();
                hit.add(headVid);
                List<Long> ids = Arrays.stream(pair[0].split(",")).map(Long::valueOf).collect(Collectors.toList());
                if (!ids.isEmpty()) {
                    for (Long id : ids) {
                        if (!hit.contains(id)) {
                            hit.add(id);
                            vidList.add(id);
                        }
                    }
                }
            }
        }
        return vidList;
    }

    private void fillVideoResult(RecallParam param, List<Long> vidList, List<Video> videosResult) {
        FilterParam filterParam = FilterParamFactory.create(param, vidList);
        FilterResult filterResult = filterService.filter(filterParam);
        if (filterResult != null && CollectionUtils.isNotEmpty(filterResult.getVideoIds())) {
            List<Long> filterIds = filterResult.getVideoIds();
            int n = filterIds.size();
            for (int i = 0; i < n; i++) {
                Video video = new Video();
                video.setVideoId(filterIds.get(i));
                video.setRovScore(n - i);
                video.setPushFrom(pushFrom());
                videosResult.add(video);
            }
        }
    }
}
