package com.artfess.sysConfig.persistence.manager.impl;

import com.alibaba.fastjson.JSONObject;
import com.artfess.base.cache.CacheManager;
import com.artfess.base.cache.ICache;
import com.artfess.base.cache.setting.CacheSetting;
import com.artfess.base.constants.CacheKeyConst;
import com.artfess.base.context.BaseContext;
import com.artfess.base.exception.ApplicationException;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.util.JsonUtil;
import com.artfess.sysConfig.enums.BaseInfoStatus;
import com.artfess.sysConfig.persistence.dao.SysDictionaryCascadeDao;
import com.artfess.sysConfig.persistence.dao.SysDictionaryDao;
import com.artfess.sysConfig.persistence.dao.SysDictionaryDetailDao;
import com.artfess.sysConfig.persistence.manager.SysDictionaryDetailManager;
import com.artfess.sysConfig.persistence.manager.SysDictionaryManager;
import com.artfess.sysConfig.persistence.model.SysDictionary;
import com.artfess.sysConfig.persistence.model.SysDictionaryCascade;
import com.artfess.sysConfig.persistence.model.SysDictionaryDetail;
import com.artfess.sysConfig.persistence.param.DictModel;
import com.artfess.sysConfig.vo.DictionaryDetailVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.helper.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Program: edp
 * @Date: 2021/3/2
 * @Author: ZQF
 * @Description: 系统字典
 */
@Service
public class SysDictionaryManagerImpl extends BaseManagerImpl<SysDictionaryDao, SysDictionary> implements SysDictionaryManager {

    @Resource
    SysDictionaryDao sysDictionaryDao;

    @Resource
    SysDictionaryDetailManager sysDictionaryDetailManager;

    @Resource
    SysDictionaryCascadeDao sysDictionaryCascadeDao;

    @Resource
    SysDictionaryDetailDao sysDictionaryDetailDao;

    @Resource
    BaseContext baseContext;

    @Resource
    CacheManager cacheManager;
    private static final CacheSetting cacheSetting = CacheSetting.buildDefault("字典缓存");
//    @Resource
//    RedisCache redisCache;

    @Override
    @Transactional
    public String saveDictionary(SysDictionary sysDictionary) throws Exception {
        // 数据合法性验证
        this.checkValidity(sysDictionary);

        ICache cache = cacheManager.getCache("", cacheSetting);

        String msg = "";
        List<SysDictionaryDetail> details = sysDictionary.getDetails();

        if (StringUtil.isBlank(sysDictionary.getId())) {
            Map<String, Object> map = new HashMap<>();
            map.put("TREE_ID_", sysDictionary.getTreeId());
            if (sysDictionary.getKindId() != 1) {
                map.put("TENANT_ID_", sysDictionary.getTenantId());
            }
            sysDictionary.setSn(this.getNextSequence(map));
            sysDictionary.setFlag(Integer.valueOf(BaseInfoStatus.DRAFT.getId()));
            msg = "新增成功";
        } else {
            //  修改的时候更新RedisConstant.SYS_DICT_ALL的缓存
//            redisCache.delLike("sys:dict:all:" + sysDictionary.getTenantId());
            cache.delLike("sys:dict:all:" + sysDictionary.getTenantId());
            msg = "修改成功";
        }
        this.saveOrUpdate(sysDictionary);
        // 保存明细
        if (details != null && details.size() > 0) {
            for (int i = 0; i < details.size(); i++) {
                SysDictionaryDetail detail = details.get(i);
                detail.setDictionaryId(sysDictionary.getId());
                if (StringUtils.isBlank(detail.getId())) {
                    Map<String, Object> criteriaMap = new HashMap<>();
                    criteriaMap.put("DICTIONARY_ID_", sysDictionary.getId());
                    detail.setSn(sysDictionaryDetailManager.getNextDetailSequence(criteriaMap));
//                    detail.setFlag(0);
                }
//                if (StringUtils.isBlank(detail.getId())) {
//                    sysDictionaryDetailDao.insert(detail);
//                } else {
//                    sysDictionaryDetailDao.updateById(detail);
//                }
                sysDictionaryDetailManager.saveOrUpdate(detail);
            }
            //  更新缓存
            String key = CacheKeyConst.SYS_DICTIONARY_KEY + ":" + sysDictionary.getCode().toUpperCase() + ":";
//            if (sysDictionary.getKindId() != 1 && StringUtils.isNotEmpty(sysDictionary.getTenantId())) {
//                key = key + sysDictionary.getTenantId().toUpperCase();
//            }
            // 单个字典
            cache.put(key, JSONObject.toJSONString(sysDictionary.getDetails()));
            //cache.put(key,sysDictionary);
//            if (redisCache.hasKey(key)) {
//                redisCache.del(key);
//            }
        }
        this.syncDictionaryRedis();
        return msg;
    }

    @Override
    @Transactional
    public void deleteDictionaries(String ids) throws Exception {
        Assert.hasText(ids, "ids不能为空");
        List<String> idsList = Arrays.asList(ids.split(","));

        ICache cache = cacheManager.getCache("", cacheSetting);
        //更新缓存
        List<SysDictionary> list = this.sysDictionaryDao.selectBatchIds(idsList);
        for (SysDictionary sysDictionary : list) {
            Assert.isTrue(BaseInfoStatus.isDraft(sysDictionary.getFlag().intValue()), String.format("%s状态不为“草稿”状态,不能删除。", new Object[]{sysDictionary.getName()}));
            String key = CacheKeyConst.SYS_DICTIONARY_KEY + ":" + sysDictionary.getCode().toUpperCase() + ":";
//            if (sysDictionary.getKindId() != 1 && StringUtils.isNotEmpty(sysDictionary.getTenantId())) {
//                key = key + sysDictionary.getTenantId().toUpperCase();
//            }

            //  目前未添加单个系统字典key
            cache.evict(key);

            //删除表的级联关系
            UpdateWrapper<SysDictionaryCascade> wrapper = new UpdateWrapper<>();
            wrapper.eq("LOWER_DIC_ID_", sysDictionary.getId());
            wrapper.or(wq -> wq.inSql("DETAIL_ID_", "select id_ from portal_sys_dictionary_detail  where DICTIONARY_ID_ = '" + sysDictionary.getId() + "'"));
            this.sysDictionaryCascadeDao.delete(wrapper);

            //删除子表数据
            UpdateWrapper<SysDictionaryDetail> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("DICTIONARY_ID_", sysDictionary.getId());
            this.sysDictionaryDetailDao.delete(updateWrapper);
        }
        //  清除缓存
//        redisUtil.delLike(CacheKeyConst.SYS_DICT_ALL + ":");
        // 清除缓存
        cache.delLike(CacheKeyConst.SYS_DICT_ALL + ":");
        this.sysDictionaryDao.deleteBatchIds(idsList);
        this.syncDictionaryRedis();
    }

    @Override
    public void updateDictionariesStatus(String ids, Integer status) {
        Assert.hasText(ids, "ids不能为空");

        ICache cache = cacheManager.getCache("", cacheSetting);

        List<String> idsList = Arrays.asList(ids.split(","));
        this.sysDictionaryDao.updateDictionariesStatus(idsList, status);
        List<SysDictionary> list = this.sysDictionaryDao.selectBatchIds(idsList);
        if (status != 1) {
            for (SysDictionary sysDictionary : list) {
                String key = CacheKeyConst.SYS_DICTIONARY_KEY + ":" + sysDictionary.getCode().toUpperCase() + ":";
//                if (sysDictionary.getKindId() != 1 && StringUtils.isNotEmpty(sysDictionary.getTenantId())) {
//                    key = key + sysDictionary.getTenantId().toUpperCase();
//                }
                //  删除缓存
//                redisUtil.del(key);
                // 单个系统字典key
                cache.evict(key);
            }
        }
        //  删除缓存
//        redisUtil.delLike(CacheConstant.SYS_DICT_ALL + ":");
        //  删除缓存
        cache.delLike(CacheKeyConst.SYS_DICT_ALL + ":");
    }

    @Override
    public SysDictionary loadDictionaryById(String id) {
        SysDictionary sysDictionary = this.sysDictionaryDao.selectById(id);
        if (sysDictionary != null) {
            SysDictionaryDetail sysDictionaryDetail = new SysDictionaryDetail();
            sysDictionaryDetail.setDictionaryId(id);
            QueryWrapper<SysDictionaryDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("DICTIONARY_ID_", id);
            List<SysDictionaryDetail> detail = sysDictionaryDetailDao.selectList(queryWrapper);
            sysDictionary.setDetails(detail);
        }
        return sysDictionary;
    }

    @Override
    public void moveDictionaries(String ids, String treeId) {
        Assert.hasText(ids, "ids不能为空");
        Assert.hasText(treeId, "treeId不能为空");
        List<String> idsList = Arrays.asList(ids.split(","));
        this.sysDictionaryDao.moveDictionaries(idsList, treeId);
    }

    @Override
    public void updateDictionariesSequence(HashMap<String, Integer> map) {
        this.updateSequence(map);
    }

    @Override
    public void syncDictionaryRedis() throws IOException {
        ICache cache = cacheManager.getCache("", cacheSetting);
        // 1.查询所有字典
        QueryWrapper<SysDictionary> queryWrapper = new QueryWrapper();
        queryWrapper.eq("flag_", 1);
        List<SysDictionary> list = this.sysDictionaryDao.selectList(queryWrapper);
        if (list.size() > 0) {
            //  2.删除所有redis缓存
//            redisUtil.delLike(CacheConstant.SYS_DICTIONARY_KEY + ":");
//            redisUtil.delLike(CacheConstant.SYS_DICT_ALL + ":");
            cache.delLike(CacheKeyConst.SYS_DICT_ALL + ":");
            Map<String, List<DictionaryDetailVo>> lowerRes = new HashMap<>();
            // 3.查询字典所有明细，并保存到redis
            for (SysDictionary sysDictionary : list) {
                String key = CacheKeyConst.SYS_DICTIONARY_KEY + ":" + sysDictionary.getCode().toUpperCase() + ":";
//                if (sysDictionary.getKindId() != 1 && StringUtils.isNotEmpty(sysDictionary.getTenantId())) {
//                    key = key + sysDictionary.getTenantId().toUpperCase();
//                }
                setDictionaryDetails(sysDictionary, key);

                // 4.查询级联字典
                List<DictionaryDetailVo> dictModelList = setDictionaryLowerDetails(sysDictionary, null);
                lowerRes.put(sysDictionary.getCode(), dictModelList);
            }
            //  5.将级联字典信息存入redis
            if (lowerRes != null && lowerRes.size() > 0) {
                String tenantId = baseContext.getCurrentTenantId();
//                redisUtil.set(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JSONObject.toJSONString(lowerRes));
//                redisUtil.expire(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JwtUtil.EXPIRE_TIME / 1000);
                cache.put(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JsonUtil.toJson(lowerRes));
                lowerRes.forEach((key , dictList) -> {
                    try {
                        cache.put(CacheKeyConst.SYS_DICTIONARY_KEY +  ":" + key.toUpperCase() + ":", JsonUtil.toJson(dictList));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

            }
        }
    }

    @Override
    public List<SysDictionary> queryLowerDictionary(String detailId) {
        return this.sysDictionaryDao.queryLowerDictionary(detailId);
    }

    @Override
    public Map<String, List<DictionaryDetailVo>> queryAllDictItems() throws IOException {
        ICache cache = cacheManager.getCache("", cacheSetting);
        Map<String, List<DictionaryDetailVo>> res = null;
        String tenantId = baseContext.getCurrentTenantId();
        //  从 Redis 中获取缓存的全部字典信息
//        res= (Map<String, List<DictionaryDetailVo>>) redisUtil.get(CacheKeyConst.SYS_DICT_ALL+":"+tenantId,HashMap.class);
        if (cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId) != null) {
            res = JsonUtil.toMap(cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId).toString());
        }
        //res = (Map<String, List<DictionaryDetailVo>>) cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, Map.class);
        if (res == null || res.size() == 0) {
            QueryWrapper<SysDictionary> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(tenantId)) {
                queryWrapper.and(wq -> wq.eq("TENANT_ID_", tenantId).or().eq("KIND_ID_", 1));
            }
            queryWrapper.eq("FLAG_", 1);
            List<SysDictionary> dictList = this.sysDictionaryDao.selectList(queryWrapper);

            res = new HashMap<>();
            for (SysDictionary dict : dictList) {
                List<DictionaryDetailVo> dictModelList = setDictionaryLowerDetails(dict, null);
                res.put(dict.getCode(), dictModelList);
            }
            //  设置 Redis 缓存
            if (res != null && res.size() > 0) {
//                redisUtil.set(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JSONObject.toJSONString(res));
//                redisUtil.expire(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JwtUtil.EXPIRE_TIME / 1000);
                cache.put(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, JsonUtil.toJson(res));
            }
        }
        return res;
    }

    @Override
    public Map<String, List<SysDictionaryDetail>> queryDictItemsByCode(String codes) throws IOException {
        ICache cache = cacheManager.getCache("", cacheSetting);

        String tenantId = baseContext.getCurrentTenantId();
        List<String> codeList = Arrays.asList(codes.split(","));
        //  从 Redis 中获取全部的字典信息
//        Map<String, List<SysDictionaryDetail>> redisDict = (Map<String, List<SysDictionaryDetail>>) redisUtil.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, HashMap.class);
        Map<String, List<SysDictionaryDetail>> redisDict = null;
        Map<String, List<SysDictionaryDetail>> res = null;
        if (cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId) != null) {
            redisDict = JsonUtil.toMap(cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId).toString());
        }
        //redisDict = (Map<String, List<SysDictionaryDetail>>) cache.get(CacheKeyConst.SYS_DICT_ALL + ":" + tenantId, HashMap.class);
        if (redisDict != null && redisDict.size() > 0) {
            res = new HashMap<>();
            for (String code : codeList) {
                res.put(code, redisDict.get(code));
            }
        }
        if (redisDict == null || res == null) {
            res = new HashMap<>();
            QueryWrapper<SysDictionary> queryWrapper = new QueryWrapper<SysDictionary>();
            if (StringUtils.isNotBlank(tenantId)) {
                queryWrapper.and(wq -> wq.eq("TENANT_ID_", tenantId).or().eq("KIND_ID_", 1));
            }
            queryWrapper.eq("FLAG_", 1).in("CODE_", codeList);
            List<SysDictionary> dictList = this.sysDictionaryDao.selectList(queryWrapper);

            for (SysDictionary dict : dictList) {
                String key = CacheKeyConst.SYS_DICTIONARY_KEY + ":" + dict.getCode().toUpperCase() + ":";
//                if (dict.getKindId() != 1 && StringUtils.isNotEmpty(dict.getTenantId())) {
//                    key = key + dict.getTenantId().toUpperCase();
//                }
                List<SysDictionaryDetail> dictModelList = setDictionaryDetails(dict, key);
                res.put(dict.getCode(), dictModelList);
            }
        }
        return res;
    }

    @Override
    public String queryDictTextByKey(String code, String key, int kindId) {
        ICache cache = cacheManager.getCache("", cacheSetting);
        String redisKey = CacheKeyConst.SYS_DICT_CACHE + "_" + code + ":" + key;
        String tenantId = null;
        if (kindId != 1) {
            tenantId = baseContext.getCurrentTenantId();
        }
        String val = "";
        // TODO 从 Redis 中获取缓存信息
//        String val = redisUtil.get(redisKey, String.class);
//        if (StringUtils.isBlank(val)) {
//            val = this.sysDictionaryDao.queryDictTextByKey(code, key, tenantId);
//            redisUtil.set(redisKey, val);
//            redisUtil.expire(redisKey, JwtUtil.EXPIRE_TIME_TWO);
//        }
/*        val = cache.get(redisKey, String.class);
        if (StringUtils.isBlank(val)) {
            // 单个字典
            val = this.sysDictionaryDao.queryDictTextByKey(code, key, tenantId);
            cache.put(redisKey, val);
        }*/
        return val;
    }

    @Override
    public List<DictModel> queryDictListItemsByCode(String code) {
        String tenantId = baseContext.getCurrentTenantId();
        return this.sysDictionaryDetailDao.queryDictModelItemsByCode(code, tenantId);
    }

    @Override
    public Map<String,List<DictModel>> dictMapByCode(String code) {
        String tenantId = baseContext.getCurrentTenantId();
        List<DictModel> modelList = this.sysDictionaryDetailDao.queryDictModelItemsByCode(code, tenantId);
        return modelList.stream().collect(Collectors.groupingBy(DictModel::getValue));
    }

    @Override
    public List<SysDictionaryDetail> queryLowerDictionaryDetail(String dictLowerId, String detailId) {
        return this.sysDictionaryDetailDao.queryLowerDictionaryDetail(dictLowerId, detailId);
    }

    /**
     * @Description: 验证字典数据的合法性
     * @Param: sysDictionary
     * @Return: void
     * @Author: ZQF
     * @Date: 2021/3/5
     */
    private void checkValidity(SysDictionary sysDictionary) {
        QueryWrapper<SysDictionary> queryWrapper = new QueryWrapper<>();
        queryWrapper.and(wq -> wq.eq("CODE_", sysDictionary.getCode()).eq(StringUtils.isNotBlank(sysDictionary.getTenantId()), "TENANT_ID_", sysDictionary.getTenantId()).or(qq -> qq.eq("CODE_", sysDictionary.getCode()).eq("KIND_ID_", 1)));
        queryWrapper.ne(StringUtils.isNotBlank(sysDictionary.getId()), "ID_", sysDictionary.getId());
        int num = this.sysDictionaryDao.selectCount(queryWrapper);
        if (num > 0) {
            throw new ApplicationException("编码【" + sysDictionary.getCode() + "】已存在，请修改后尝试！");
        }
    }

    /**
     * @Description: 查询字典明细存入缓存
     * @Param: sysDictionary
     * @Param: key
     * @Return: java.util.List<com.artfess.portal.model.SysDictionaryDetail>
     * @Author: ZQF
     * @Date: 2021/3/17
     */
    private List<SysDictionaryDetail> setDictionaryDetails(SysDictionary sysDictionary, String key) {
        ICache cache = cacheManager.getCache("", cacheSetting);
        QueryWrapper<SysDictionaryDetail> detailWrapper = new QueryWrapper();
        detailWrapper.eq("FLAG_", 1);
        detailWrapper.eq("DICTIONARY_ID_", sysDictionary.getId());
        detailWrapper.orderByAsc("SN_");
        List<SysDictionaryDetail> detailEntityList = sysDictionaryDetailDao.selectList(detailWrapper);
        //  目前未添加单个系统字典key
        cache.put(key, JSONObject.toJSONString(detailEntityList));
        return detailEntityList;
    }

    /**
     * @Description: 查询字典明细（包括明细关联的下级字典）
     * @Param: sysDictionary
     * @Param: detailId
     * @Return: java.util.List<com.artfess.portal.params.DictionaryDetailVo>
     * @Author: ZQF
     * @Date: 2021/3/17
     */
    private List<DictionaryDetailVo> setDictionaryLowerDetails(SysDictionary sysDictionary, String detailId) {
        // 1.查询明细
        QueryWrapper<SysDictionaryDetail> detailWrapper = new QueryWrapper();
        detailWrapper.eq("FLAG_", 1);
        detailWrapper.eq("DICTIONARY_ID_", sysDictionary.getId());
        detailWrapper.inSql(StringUtils.isNotEmpty(detailId), "id_", "select c.LOWER_DETAIL_ID_ from portal_sys_dictionary_cascade c where c.DETAIL_ID_='" + detailId + "'");
        detailWrapper.orderByAsc("SN_");
        List<SysDictionaryDetail> detailEntityList = sysDictionaryDetailDao.selectList(detailWrapper);
        List<DictionaryDetailVo> detailList = null;
        // 2.查询明细级联的下级字典信息
        if (detailEntityList != null) {
            detailList = new ArrayList<DictionaryDetailVo>();
            Map<String, List<DictionaryDetailVo>> res = null;
            for (SysDictionaryDetail detail : detailEntityList) {
                DictionaryDetailVo dicDetailVo = new DictionaryDetailVo();
                dicDetailVo.setId(detail.getId());
                dicDetailVo.setDictionaryId(detail.getDictionaryId());
                dicDetailVo.setName(detail.getName());
                dicDetailVo.setValue(detail.getValue());
                dicDetailVo.setSequence(detail.getSn());
                List<SysDictionary> list = queryLowerDictionary(detail.getId());
                for (SysDictionary dict : list) {
                    res = new HashMap<>();
                    List<DictionaryDetailVo> dictModelList = setDictionaryLowerDetails(dict, detail.getId());
                    res.put(dict.getCode(), dictModelList);
                    dicDetailVo.setLowerDic(res);
                }
                detailList.add(dicDetailVo);
            }
        }

        return detailList;
    }

}
