package com.njcn.gather.system.dictionary.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.db.mybatisplus.constant.DbConstant;
import com.njcn.gather.system.dictionary.mapper.DictDataMapper;
import com.njcn.gather.system.dictionary.pojo.dto.DictDataCache;
import com.njcn.gather.system.dictionary.pojo.param.DictDataParam;
import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.pojo.po.DictType;
import com.njcn.gather.system.dictionary.pojo.vo.DictDataExcel;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import com.njcn.gather.system.pojo.enums.SystemResponseEnum;
import com.njcn.gather.system.util.ExportFileNameUtil;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.pojo.dto.SimpleDTO;
import com.njcn.web.pojo.dto.SimpleTreeDTO;
import com.njcn.web.utils.ExcelUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author hongawen
 * @since 2021-12-13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DictDataServiceImpl extends ServiceImpl<DictDataMapper, DictData> implements IDictDataService {

    @Override
    public Page<DictData> getDictDataByTypeId(DictDataParam.QueryParam queryParam) {
        QueryWrapper<DictData> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(queryParam)) {
            queryWrapper.like(StrUtil.isNotBlank(queryParam.getName()), "sys_dict_data.name", queryParam.getName())
                    .like(StrUtil.isNotBlank(queryParam.getCode()), "sys_dict_data.code", queryParam.getCode());
            //排序
            if (ObjectUtil.isAllNotEmpty(queryParam.getSortBy(), queryParam.getOrderBy())) {
                queryWrapper.orderBy(true, queryParam.getOrderBy().equals(DbConstant.ASC), StrUtil.toUnderlineCase(queryParam.getSortBy()));
            } else {
                //没有排序参数，默认根据sort字段排序，没有排序字段的，根据updateTime更新时间排序
                queryWrapper.orderBy(true, true, "sys_dict_data.sort").orderByDesc("sys_dict_data.update_time");
            }
        } else {
            queryWrapper.orderBy(true, true, "sys_dict_data.sort").orderByDesc("sys_dict_data.update_time");
        }
        queryWrapper.ne("sys_dict_data.state", DataStateEnum.DELETED.getCode())
                .eq("sys_dict_data.type_id", queryParam.getTypeId());
        //初始化分页数据
        return this.baseMapper.selectPage(new Page<>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)), queryWrapper);
    }

    @Override
    public List<DictData> listDictDataByTypeId(String typeId) {
        return this.lambdaQuery().eq(DictData::getTypeId, typeId).eq(DictData::getState, DataStateEnum.ENABLE.getCode()).list();
    }

    @Override
    public List<DictData> getDictDataByTypeId(String typeId) {
        return this.lambdaQuery().eq(DictData::getTypeId, typeId).eq(DictData::getState, DataStateEnum.ENABLE.getCode()).list();
    }

    @Override
    @Transactional
    public boolean addDictData(DictDataParam dictDataParam) {
        dictDataParam.setName(dictDataParam.getName().trim());
        checkDicDataName(dictDataParam, false);
        DictData dictData = new DictData();
        BeanUtil.copyProperties(dictDataParam, dictData);
        //默认为正常状态
        dictData.setState(DataStateEnum.ENABLE.getCode());
        return this.save(dictData);
    }


    @Override
    @Transactional
    public boolean updateDictData(DictDataParam.UpdateParam updateParam) {
        updateParam.setName(updateParam.getName().trim());
        checkDicDataName(updateParam, true);
        DictData dictData = new DictData();
        BeanUtil.copyProperties(updateParam, dictData);
        return this.updateById(dictData);
    }

    @Override
    @Transactional
    public boolean deleteDictData(List<String> ids) {
        return this.lambdaUpdate()
                .set(DictData::getState, DataStateEnum.DELETED.getCode())
                .in(DictData::getId, ids)
                .update();
    }


    @Override
    public DictData getDictDataById(String id) {
        return this.lambdaQuery().eq(DictData::getId, id).eq(DictData::getState, DataStateEnum.ENABLE.getCode()).one();
    }

    @Override
    public DictData getDictDataByName(String name) {
        return this.lambdaQuery().eq(DictData::getName, name).eq(DictData::getState, DataStateEnum.ENABLE.getCode()).one();
    }

    @Override
    public DictData getDictDataByCode(String code) {
        LambdaQueryWrapper<DictData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DictData::getCode, code)
                .eq(DictData::getState, DataStateEnum.ENABLE.getCode());
        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    public List<SimpleTreeDTO> dictDataCache() {
        MPJLambdaWrapper<DictData> dictTypeWrapper = new MPJLambdaWrapper<DictData>()
                .eq(DictData::getState, DataStateEnum.ENABLE.getCode())
                .selectAll(DictData.class)
                .selectAs(DictType::getId, DictDataCache::getTypeId)
                .selectAs(DictType::getName, DictDataCache::getTypeName)
                .selectAs(DictType::getCode, DictDataCache::getTypeCode)
                .leftJoin(DictType.class, DictType::getId, DictData::getTypeId)
                .eq(DictType::getState, DataStateEnum.ENABLE.getCode());
        List<DictDataCache> allDictData = this.getBaseMapper().selectJoinList(DictDataCache.class, dictTypeWrapper);

        Map<Object, List<DictDataCache>> dictDataCacheMap = allDictData.stream()
                .collect(Collectors.groupingBy(DictDataCache::getTypeId));
        return dictDataCacheMap.keySet().stream().map(typeId -> {
            SimpleTreeDTO simpleTreeDTO = new SimpleTreeDTO();
            List<DictDataCache> dictDataCaches = dictDataCacheMap.get(typeId);
            List<SimpleDTO> simpleDTOList = dictDataCaches.stream().map(dictDataCache -> {
                simpleTreeDTO.setCode(dictDataCache.getTypeCode());
                simpleTreeDTO.setId(dictDataCache.getTypeId());
                simpleTreeDTO.setName(dictDataCache.getTypeName());
                SimpleDTO simpleDTO = new SimpleDTO();
                simpleDTO.setCode(dictDataCache.getCode());
                simpleDTO.setId(dictDataCache.getId());
                simpleDTO.setName(dictDataCache.getName());
                simpleDTO.setSort(dictDataCache.getSort());
                simpleDTO.setValue(dictDataCache.getValue());
                simpleDTO.setAlgoDescribe(dictDataCache.getAlgoDescribe());
                return simpleDTO;
            }).sorted(Comparator.comparing(SimpleDTO::getSort)).collect(Collectors.toList());
            simpleTreeDTO.setChildren(simpleDTOList);
            return simpleTreeDTO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void exportDictData(DictDataParam.QueryParam queryParam) {
        QueryWrapper<DictData> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(queryParam)) {
            queryWrapper.like(StrUtil.isNotBlank(queryParam.getName()), "sys_dict_data.name", queryParam.getName())
                    .like(StrUtil.isNotBlank(queryParam.getCode()), "sys_dict_data.code", queryParam.getCode());
            //排序
            if (ObjectUtil.isAllNotEmpty(queryParam.getSortBy(), queryParam.getOrderBy())) {
                queryWrapper.orderBy(true, queryParam.getOrderBy().equals(DbConstant.ASC), StrUtil.toUnderlineCase(queryParam.getSortBy()));
            } else {
                //没有排序参数，默认根据sort字段排序，没有排序字段的，根据updateTime更新时间排序
                queryWrapper.orderBy(true, true, "sys_dict_data.sort").orderByDesc("sys_dict_data.update_time");
            }
        }
        queryWrapper.ne("sys_dict_data.state", DataStateEnum.DELETED.getCode())
                .eq("sys_dict_data.type_id", queryParam.getTypeId());
        List<DictData> dictDatas = this.list(queryWrapper);
        List<DictDataExcel> dictDataExcels = BeanUtil.copyToList(dictDatas, DictDataExcel.class);
        ExcelUtil.exportExcel(ExportFileNameUtil.appendToday("字典数据导出数据.xlsx"), "字典数据", DictDataExcel.class, dictDataExcels);
    }

    @Override
    @Transactional
    public boolean deleteDictDataByDictTypeId(List<String> ids) {
        return this.lambdaUpdate().in(DictData::getTypeId, ids).set(DictData::getState, DataStateEnum.DELETED.getCode()).update();
    }


    /**
     * 校验参数，检查是否存在相同名称的字典类型
     */
    private void checkDicDataName(DictDataParam dictDataParam, boolean isExcludeSelf) {
        LambdaQueryWrapper<DictData> dictDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dictDataLambdaQueryWrapper.eq(DictData::getTypeId, dictDataParam.getTypeId())
                .eq(DictData::getState, DataStateEnum.ENABLE.getCode())
                .and(w -> w.eq(DictData::getName, dictDataParam.getName()).or().eq(DictData::getCode, dictDataParam.getCode()));
        //更新的时候，需排除当前记录
        if (isExcludeSelf) {
            if (dictDataParam instanceof DictDataParam.UpdateParam) {
                dictDataLambdaQueryWrapper.ne(DictData::getId, ((DictDataParam.UpdateParam) dictDataParam).getId());
            }
        }
        int countByAccount = this.count(dictDataLambdaQueryWrapper);
        //大于等于1个则表示重复
        if (countByAccount >= 1) {
            throw new BusinessException(SystemResponseEnum.DICT_DATA_REPEAT);
        }
    }
}
