package com.yd.csf.service.component;

import com.yd.common.constant.RedisConstants;
import com.yd.common.utils.RedisUtil;
import com.yd.user.feign.client.sysdict.ApiSysDictFeignClient;
import com.yd.user.feign.request.sysdict.GetDictTypeListRequest;
import com.yd.user.feign.response.sysdict.GetDictItemListByDictTypeResponse;
import com.yd.user.feign.response.sysdict.GetDictTypeListResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class DictCacheService {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ApiSysDictFeignClient apiSysDictFeignClient;

    /**
     * 获取字典列表，缓存未命中或缺少指定类型时，按需从Feign拉取并合并写入Redis
     *
     * @param dictTypes 需要的字典类型编码
     */
    public List<GetDictItemListByDictTypeResponse> getDictList(String... dictTypes) {
        if (dictTypes == null || dictTypes.length == 0) {
            return Collections.emptyList();
        }

        // 快速路径：从Redis获取缓存
        List<GetDictItemListByDictTypeResponse> cached = redisUtil.getCacheObject(RedisConstants.DICT_LIST);

        // 收集需要拉取的dictType
        Set<String> neededTypes = new HashSet<>(Arrays.asList(dictTypes));
        if (CollectionUtils.isEmpty(cached)) {
            // 缓存完全为空
            return fetchAndCache(neededTypes, Collections.emptyList());
        } else {
            // 检查缓存中已有哪些类型
            Set<String> cachedTypes = cached.stream()
                    .filter(Objects::nonNull)
                    .map(GetDictItemListByDictTypeResponse::getDictType)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            Set<String> missingTypes = new HashSet<>(neededTypes);
            missingTypes.removeAll(cachedTypes);

            if (missingTypes.isEmpty()) {
                return cached;
            }
            return fetchAndCache(missingTypes, cached);
        }
    }

    /**
     * 加锁从Feign拉取缺失的字典类型，合并到已有缓存并写回Redis
     */
    private List<GetDictItemListByDictTypeResponse> fetchAndCache(Set<String> missingTypes, List<GetDictItemListByDictTypeResponse> existingCache) {
        synchronized (this) {
            // 双重检查：再次从Redis读取，防止并发时重复拉取
            List<GetDictItemListByDictTypeResponse> cached = redisUtil.getCacheObject(RedisConstants.DICT_LIST);
            if (!CollectionUtils.isEmpty(cached)) {
                Set<String> cachedTypes = cached.stream()
                        .filter(Objects::nonNull)
                        .map(GetDictItemListByDictTypeResponse::getDictType)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());

                missingTypes.removeAll(cachedTypes);
                if (missingTypes.isEmpty()) {
                    return cached;
                }
                existingCache = cached;
            }

            // 从Feign拉取缺失类型
            List<GetDictItemListByDictTypeResponse> fetched = fetchFromFeign(missingTypes);

            // 合并并去重
            List<GetDictItemListByDictTypeResponse> merged = mergeCache(existingCache, fetched);

            if (!CollectionUtils.isEmpty(merged)) {
                redisUtil.setCacheObject(RedisConstants.DICT_LIST, merged);
            }
            return merged;
        }
    }

    /**
     * 调用Feign拉取指定字典类型的数据
     */
    private List<GetDictItemListByDictTypeResponse> fetchFromFeign(Set<String> dictTypes) {
        try {
            GetDictTypeListRequest request = new GetDictTypeListRequest();
            request.setTypeList(new ArrayList<>(dictTypes));

            List<GetDictTypeListResponse> dictTypeResponses = apiSysDictFeignClient.getByDictTypeList(request).getData();

            if (CollectionUtils.isEmpty(dictTypeResponses)) {
                log.warn("Feign返回空字典列表, 请求类型: {}", dictTypes);
                return Collections.emptyList();
            }

            return dictTypeResponses.stream()
                    .filter(Objects::nonNull)
                    .filter(dtr -> dtr.getDictItemList() != null)
                    .flatMap(dtr -> dtr.getDictItemList().stream())
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("从Feign拉取字典数据失败, 请求类型: {}", dictTypes, e);
            return Collections.emptyList();
        }
    }

    /**
     * 合并已有缓存与新拉取数据，按 dictType + itemValue 去重
     */
    private List<GetDictItemListByDictTypeResponse> mergeCache(
            List<GetDictItemListByDictTypeResponse> existing,
            List<GetDictItemListByDictTypeResponse> fetched) {

        Map<String, GetDictItemListByDictTypeResponse> merged = new LinkedHashMap<>();

        // 先放入已有缓存
        for (GetDictItemListByDictTypeResponse item : existing) {
            if (item != null && item.getDictType() != null && item.getItemValue() != null) {
                String key = item.getDictType() + ":" + item.getItemValue();
                merged.put(key, item);
            }
        }

        // 再放入新拉取数据（覆盖相同key的旧值）
        for (GetDictItemListByDictTypeResponse item : fetched) {
            if (item != null && item.getDictType() != null && item.getItemValue() != null) {
                String key = item.getDictType() + ":" + item.getItemValue();
                merged.put(key, item);
            }
        }

        return new ArrayList<>(merged.values());
    }
}
