package com.tzld.longarticle.recommend.server.service.filter;

import com.google.common.collect.Lists;
import com.tzld.longarticle.recommend.server.common.ThreadPoolFactory;
import com.tzld.longarticle.recommend.server.service.ServiceBeanFactory;
import com.tzld.longarticle.recommend.server.service.filter.strategy.SimilarityStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class FilterService {
    private final ExecutorService pool = ThreadPoolFactory.filterPool();

    public FilterResult filter(FilterParam param) {
        List<Long> videoIds = viewFilter(param);

        return new FilterResult(videoIds);
    }

    protected List<Long> viewFilter(FilterParam param) {

        List<FilterStrategy> strategies = getStrategies(param);
        CountDownLatch cdl = new CountDownLatch(strategies.size());
        List<Future<List<Long>>> futures = new ArrayList<>();
        for (final FilterStrategy strategy : strategies) {
            Future<List<Long>> future = pool.submit(() -> {
                List<Long> result = strategy.filter(param);
                cdl.countDown();
                return result;
            });
            futures.add(future);
        }
        try {
            cdl.await(1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.error("filter error", e);
            return null;
        }

        List<List<Long>> videoIds = new ArrayList<>();
        for (Future<List<Long>> f : futures) {
            try {
                videoIds.add(f.get());
            } catch (Exception e) {
                log.error("future get error ", e);
            }
        }
        if (CollectionUtils.isEmpty(videoIds)) {
            return Collections.emptyList();
        }
        List<Long> result = Lists.newArrayList(param.getVideoIds());
        for (int i = 0; i < videoIds.size(); ++i) {
            result.retainAll(videoIds.get(i));
        }
        return result;
    }

    private List<FilterStrategy> getStrategies(FilterParam param) {
        List<FilterStrategy> strategies = new ArrayList<>();
        strategies.add(ServiceBeanFactory.getBean(SimilarityStrategy.class));

        return strategies;
    }
}
