package com.qiaoba.module.system.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.api.system.entity.SysDictData;
import com.qiaoba.api.system.entity.param.SysDictDataParam;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.constant.DictConstant;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.common.database.entity.PageQuery;
import com.qiaoba.common.database.entity.TableDataInfo;
import com.qiaoba.common.redis.service.RedisService;
import com.qiaoba.module.system.mapper.SysDictDataMapper;
import com.qiaoba.module.system.service.SysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 字典类型数据管理 服务层实现
 *
 * @author ailanyin
 * @version 1.0
 * @since 2022-09-22 04:20:28
 */
@Service
@RequiredArgsConstructor
public class SysDictDataServiceImpl implements SysDictDataService {

    private final SysDictDataMapper sysDictDataMapper;
    private final RedisService redisService;

    @Override
    public String selectDictLabel(String dictType, String dictValue) {
        QueryWrapper<SysDictData> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysDictData::getDictType, dictType)
                .eq(SysDictData::getDictValue, dictValue);
        SysDictData sysDictData = sysDictDataMapper.selectOne(wrapper);
        return Objects.isNull(sysDictData) ? StrUtil.EMPTY : sysDictData.getDictLabel();
    }

    @Override
    public SysDictData selectById(String dictCode) {
        return sysDictDataMapper.selectById(dictCode);
    }

    @Override
    public int deleteByIds(List<String> ids) {
        SysDictData sysDictData = selectById(ids.get(0));
        int result = sysDictDataMapper.deleteBatchIds(ids);
        if (result > BaseConstant.HANDLE_ERROR) {
            cacheDictData(sysDictData.getDictType());
        }
        return result;
    }

    @Override
    public int insert(SysDictData sysDictData) {
        checkAllowAddOrUpdate(sysDictData);
        sysDictData.setCreateTime(new Date());
        sysDictData.setCreateUser(SecurityUtil.getLoginUsername());
        int result = sysDictDataMapper.insert(sysDictData);
        if (result > BaseConstant.HANDLE_ERROR) {
            cacheDictData(sysDictData.getDictType());
        }
        return result;
    }

    @Override
    public int update(SysDictData sysDictData) {
        checkAllowAddOrUpdate(sysDictData);
        sysDictData.setUpdateTime(new Date());
        sysDictData.setUpdateUser(SecurityUtil.getLoginUsername());
        int result = sysDictDataMapper.updateById(sysDictData);
        if (result > BaseConstant.HANDLE_ERROR) {
            cacheDictData(sysDictData.getDictType());
        }
        return result;
    }

    @Override
    public TableDataInfo selectPageList(SysDictDataParam param, PageQuery pageQuery) {
        return TableDataInfo.build(sysDictDataMapper.selectPage(pageQuery.build(), param2Wrapper(param)));
    }

    @Override
    public List<SysDictData> selectList(SysDictDataParam param) {
        return sysDictDataMapper.selectList(param2Wrapper(param));
    }

    @Override
    public void resetDictCache() {
        redisService.del(redisService.getKeys(DictConstant.SYS_DICT_KEY + "*"));
        Map<String, List<SysDictData>> dictDataMap = selectList(new SysDictDataParam()).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet()) {
            redisService.set(DictConstant.SYS_DICT_KEY + entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
        }
    }

    @Override
    public List<SysDictData> selectByDictType(String dictType) {
        return sysDictDataMapper.selectList(param2Wrapper(new SysDictDataParam(dictType)));
    }

    private QueryWrapper<SysDictData> param2Wrapper(SysDictDataParam param) {
        QueryWrapper<SysDictData> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .orderByAsc(SysDictData::getDictSort)
                .like(StrUtil.isNotBlank(param.getDictType()), SysDictData::getDictType, param.getDictType())
                .like(StrUtil.isNotBlank(param.getDictLabel()), SysDictData::getDictLabel, param.getDictLabel())
                .eq(StrUtil.isNotBlank(param.getStatus()), SysDictData::getStatus, param.getStatus());
        return wrapper;
    }

    private void checkAllowAddOrUpdate(SysDictData sysDictData) {
        String dictLabel = sysDictDataMapper.checkDictLabelUnique(sysDictData);
        if (StrUtil.isNotBlank(dictLabel)) {
            throw new ServiceException("数据标签已存在");
        }

        String dictValue = sysDictDataMapper.checkDictValueUnique(sysDictData);
        if (StrUtil.isNotBlank(dictValue)) {
            throw new ServiceException("数据键值已存在");
        }
    }

    private void cacheDictData(String dictType) {
        List<SysDictData> dictData = selectByDictType(dictType);
        if (CollUtil.isNotEmpty(dictData)) {
            redisService.set(DictConstant.SYS_DICT_KEY + dictType, dictData.stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
        } else {
            redisService.del(DictConstant.SYS_DICT_KEY + dictType);
        }
    }

    @Override
    public List<SysDictData> selectFromCache(String dictType) {
        return redisService.getObjectList(DictConstant.SYS_DICT_KEY + dictType, SysDictData.class);
    }
}
