package com.hz.pm.api.meta.helper.basic;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.NumberUtil;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.hz.pm.api.meta.assembler.MetaTagAssembler;
import com.hz.pm.api.meta.helper.TagCache;
import com.hz.pm.api.meta.model.dto.TagDTO;
import com.hz.pm.api.meta.model.dto.TagTreeDTO;
import com.hz.pm.api.meta.service.IMetaTagService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.springframework.beans.factory.InitializingBean;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author liuxinxin
 * @date 2022/12/22 上午11:56
 */
@Slf4j
@RequiredArgsConstructor
public abstract class AbstractTagsCache implements InitializingBean, TagCache {


    protected static final int MAX_LEVEL = 4;

    private final IMetaTagService metaTagService;

    protected LoadingCache<String, List<TagTreeDTO>> tagsCache;

    protected Map<String, TagDTO> tagCacheMap = new ConcurrentHashMap<>();

    @Override
    public void afterPropertiesSet() {
        tagsCache = Caffeine.newBuilder()
                .refreshAfterWrite(7, TimeUnit.DAYS)
                .build(new CacheLoader<String, List<TagTreeDTO>>() {

                    @Override
                    public List<TagTreeDTO> load(@NonNull String key) {
                        log.info("刷新当前标签树：{}", key);
                        // 查询全部
                        List<TagDTO> tags = metaTagService.queryLeLevel(Integer.parseInt(key));
                        putToTagMap(tags);
                        return toTree(MetaTagAssembler.convert(tags));
                    }

                    @Override
                    public @NonNull Map<String, List<TagTreeDTO>> loadAll(@NonNull Iterable<? extends @NonNull String> keys) {
                        if (CollUtil.isEmpty(keys)) {
                            return Collections.emptyMap();
                        }
                        Optional<Integer> maxLevel = IterUtil.toList(keys).stream()
                                .map(Integer::parseInt)
                                .max(Comparator.comparingInt(Integer::intValue));
                        if (!maxLevel.isPresent()) {
                            return Collections.emptyMap();
                        }
                        Integer maxLevelVal = maxLevel.get();
                        log.info("刷新当前标签树：最大层级为 -> {}", maxLevelVal);
                        List<TagDTO> allTags = metaTagService.queryLeLevel(maxLevelVal);
                        putToTagMap(allTags);
                        Map<String, List<TagTreeDTO>> mapByKeys = new HashMap<>();
                        keys.forEach(key -> {
                            int currLevel = Integer.parseInt(key);
                            List<TagDTO> tagsByLevel = allTags.stream()
                                    .filter(w -> w.getTagLevel() <= currLevel)
                                    .collect(Collectors.toList());
                            mapByKeys.put(String.valueOf(currLevel), toTree(MetaTagAssembler.convert(tagsByLevel)));
                        });
                        return mapByKeys;
                    }

                });
        // 初始化所有tag
        initAllTags();
    }

    private void putToTagMap(List<TagDTO> tagDTOList) {
        tagDTOList.forEach(tagDTO -> tagCacheMap.put(tagDTO.getTagCode(), tagDTO));
    }

    private List<TagTreeDTO> toTree(List<TagTreeDTO> tagTreeList) {
        List<TagTreeDTO> nodeList = new ArrayList<>();
        for (TagTreeDTO node : tagTreeList) {
            String parentCode = node.getParentCode();
            if ("-1".equals(parentCode) || Objects.isNull(parentCode)) {
                nodeList.add(node);
            }
            node.setChildren(getChildren(node.getTagCode(), tagTreeList));
        }
        return nodeList;
    }

    public void initAllTags() {
        List<String> allLevels = Arrays.stream(NumberUtil.range(1, MAX_LEVEL))
                .mapToObj(String::valueOf)
                .collect(Collectors.toList());
        tagsCache.getAll(allLevels);
    }

    protected List<TagTreeDTO> getChildren(String tagCode, List<TagTreeDTO> list) {
        List<TagTreeDTO> childList = new ArrayList<>();
        for (TagTreeDTO tagTreeDTO : list) {
            if (tagCode.equals(tagTreeDTO.getParentCode())) {
                childList.add(tagTreeDTO);
            }
        }
        for (TagTreeDTO tagTreeDTO : childList) {
            tagTreeDTO.setChildren(getChildren(tagTreeDTO.getTagCode(), list));
        }
        if (CollectionUtils.isEmpty(childList)) {
            return Collections.emptyList();
        }
        return childList;
    }

}
