package com.ningdatech.pmapi.meta.helper.basic;

import cn.hutool.core.lang.Assert;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.ningdatech.pmapi.meta.assembler.MetaTagAssembler;
import com.ningdatech.pmapi.meta.helper.TagCache;
import com.ningdatech.pmapi.meta.model.dto.TagDTO;
import com.ningdatech.pmapi.meta.model.dto.TagTreeDTO;
import com.ningdatech.pmapi.meta.service.IMetaTagService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

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
 */
public abstract class AbstractTagsCache implements InitializingBean, TagCache {

    protected static final int MAX_LEVEL = 4;

    @Autowired
    private IMetaTagService iMetaTagService;

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

    protected Map<String, TagDTO> tagDtoMap;

    @Override
    public void afterPropertiesSet() {
        tagsCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
                .refreshAfterWrite(5, TimeUnit.MINUTES)
                .build(key -> {
                    // 查询全部
                    List<TagDTO> tagDTOList = iMetaTagService.queryAll();
                    Assert.isTrue(CollectionUtils.isNotEmpty(tagDTOList), "MetaTags queryAll is Empty");
                    tagDtoMap = buildCateMap(tagDTOList);
                    List<TagDTO> tagInLevel = tagDTOList.stream().filter(tagDto -> {
                        // 只过滤出小于等于level的tag
                        if (Objects.isNull(tagDto.getTagLevel())) {
                            return false;
                        }
                        return Integer.parseInt(key) >= tagDto.getTagLevel();
                    }).collect(Collectors.toList());
                    List<TagTreeDTO> treeDtos = MetaTagAssembler.toTagTreeDTOList(tagInLevel);
                    return toTreeStructure(treeDtos);
                });
        warmUp();
    }

    private Map<String, TagDTO> buildCateMap(List<TagDTO> tagDTOList) {
        Map<String, TagDTO> tagDtoMapTemp = new ConcurrentHashMap<>(1024);
        tagDTOList.forEach(tagDTO -> tagDtoMapTemp.put(tagDTO.getTagCode(), tagDTO));
        return tagDtoMapTemp;
    }

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

    public void warmUp() {
        for (int level = 1; level <= MAX_LEVEL; level++) {
            tagsCache.get(level + "");
        }
    }

    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;
    }

}
