package com.jwipc.sys.logic.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.jwipc.exception.DaoException;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.dto.DictDTO;
import com.jwipc.sys.convert.DictConvert;
import com.jwipc.sys.dto.*;
import com.jwipc.sys.entity.Dict;
import com.jwipc.sys.entity.DictType;
import com.jwipc.sys.logic.DictLogic;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.sys.model.po.DictByTypePO;
import com.jwipc.sys.model.query.DictListQuery;
import com.jwipc.sys.model.query.DictTypeQuery;
import com.jwipc.sys.service.IDictService;
import com.jwipc.sys.service.IDictTypeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DictLogicImpl implements DictLogic {
    private final IDictService dictService;
    private final IDictTypeService dictTypeService;
    private final DictConvert dictConvert;
    private final FileLogic fileLogic;

    @Override
    public List<com.jwipc.sys.dto.DictDTO> getDicByType(String type) {
        List<DictByTypePO> dict = dictService.findDictByType(type);
        return dictConvert.byTypePOs2DTOs(dict);
    }

    @Override
    public PageView list(DictListQuery query) {
        final Page<DictType> page = PageUtil.toPage(query);
        final LambdaQueryWrapper<DictType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .like(StrUtil.isNotEmpty(query.getName()), DictType::getName, query.getName())
                .like(StrUtil.isNotEmpty(query.getCode()), DictType::getCode, query.getCode())
                .orderByDesc(DictType::getCreateTime);
        final List<DictType> list = dictTypeService.list(page, queryWrapper);
        List<DictTypeListDTO> list1 = dictConvert.entities2ListDTOs(list);
        return PageUtil.getPV(list1, page.getTotal());
    }

    @Override
    public DictEditDTO getForAddOrEdit(Long id) {
        final DictType byId = dictTypeService.getById(id);
        DictEditDTO dictEditDTO = new DictEditDTO();
        if (Objects.nonNull(byId)) {
            dictEditDTO = dictConvert.entity2EditDTO(byId);
        }
        return dictEditDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdate(DictEditDTO dictEditDTO) {
        //有id表示修改，如果无id表示新增
        final LambdaQueryWrapper<DictType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DictType::getCode, dictEditDTO.getCode())
                .ne(Objects.nonNull(dictEditDTO.getId()), DictType::getId, dictEditDTO.getId());
        final DictType one = dictTypeService.getOne(queryWrapper);
        if (Objects.nonNull(one)) {
            throw new DaoException("字典类型值已经存在!");
        }
        DictType dictType = dictConvert.editDTO2Entity(dictEditDTO);
        if (Objects.nonNull(dictType)) {
            dictType.setUpdateTime(LocalDateTime.now());
            dictType.setUpdateUser(LoginUtil.getUserId());
        } else {
            dictType.setCreateTime(LocalDateTime.now());
            dictType.setCreateUser(LoginUtil.getUserId());
        }
        dictTypeService.saveOrUpdate(dictType);
    }

    @Override
    public PageView itemList(DictTypeQuery query) {
        final Page<Dict> page = PageUtil.toPage(query);
        List<Dict> list = dictService.list(page,
                new LambdaQueryWrapper<Dict>().eq(Dict::getTypeId, query.getDictType())
                        .orderBy(true, true, Dict::getSort));
        List<DictItemListDTO> list1 = dictConvert.entities2ItemListDTOs(list);
        return PageUtil.getPV(list1, page.getTotal());
    }
    @Override
    public List<DictItemListDTO> listAll(DictTypeQuery query) {
//        List<QmAuditManagePO> qmAuditManagePOS = qmAuditManageService.findPageByQuery(null, query);
        List<Dict> list = dictService.list(null,
                new LambdaQueryWrapper<Dict>().eq(Dict::getTypeId, query.getDictType()));
        return dictConvert.entities2ItemListDTOs(list);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void itemSaveOrUpdate(DictItemEditDTO dictEditDTO) {
        Dict dict = dictConvert.itemEditDTO2eintity(dictEditDTO);
        //需要判断字典值是否存在
        final LambdaQueryWrapper<Dict> queryWrapper = new LambdaQueryWrapper<Dict>().eq(Dict::getTypeId,
                        dictEditDTO.getTypeId())
                .eq(Dict::getCode, dictEditDTO.getCode())
                .ne(Objects.nonNull(dictEditDTO.getId()), Dict::getId, dictEditDTO.getId());
        final Dict one = dictService.getOne(queryWrapper);
        if (Objects.nonNull(one)) {
            throw new DaoException("字典值已存在!");
        }
        if (Objects.nonNull(dict.getId())) {
            dict.setUpdateTime(LocalDateTime.now());
            dict.setUpdateUser(LoginUtil.getUserId());
        } else {
            dict.setCreateTime(LocalDateTime.now());
            dict.setCreateUser(LoginUtil.getUserId());
        }
        dictService.saveOrUpdate(dict);
    }

    @Override
    public DictItemEditDTO getForAddOrEditItem(Long id) {
        final Dict byId = dictService.getById(id);
        DictItemEditDTO dictEditDTO = new DictItemEditDTO();
        if (Objects.nonNull(byId)) {
            dictEditDTO = dictConvert.entity2EditItemDTO(byId);
        }
        return dictEditDTO;
    }

    @Override
    public void itemRemove(Long id) {
        dictService.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void itemImportData(MultipartFile fileId, Long dictTypeId) {
        //这个地方需要通过文件id获取文件，然后获取导入的数据
        //查询当前的所有字典明细
        final List<Dict> list = dictService.list(new LambdaQueryWrapper<Dict>().eq(Dict::getTypeId, dictTypeId));
        final List<String> dbDictCodes = list.stream().map(Dict::getCode).toList();
        List<DictItemImportDTO> cachedDataList = ListUtils.newArrayList();
        Set<String> currentDictCodes = Sets.newConcurrentHashSet();
        try {
            EasyExcel.read(fileId.getInputStream(), DictItemImportDTO.class, new ReadListener<DictItemImportDTO>() {
                @Override
                public void invoke(DictItemImportDTO data, AnalysisContext context) {
                    final String code = data.getCode();
                    if (Strings.isNullOrEmpty(code)) {
                        throw new DaoException("编码不能为空!");
                    }
                    if (Strings.isNullOrEmpty(data.getName())) {
                        throw new DaoException("名称不能为空!");
                    }
                    if (dbDictCodes.contains(code) || currentDictCodes.contains(code)) {
                        throw new DaoException(StrUtil.concat(true, code, "编码重复!"));
                    }
                    currentDictCodes.add(code);
                    cachedDataList.add(data);
                }
                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                }
            }).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<Dict> dicts = dictConvert.importDTOs2Entites(cachedDataList);
        for (Dict dict : dicts) {
            dict.setCreateUser(LoginUtil.getUserId());
            dict.setCreateTime(LocalDateTime.now());
            dict.setTypeId(dictTypeId);
        }
        dictService.saveBatch(dicts);
    }

    @Override
    public Map<String, List<DictDTO>> getDicByTypes(String types) {
        final List<String> typeCodes = new HashSet<>(StrUtil.split(types, StrUtil.COMMA)).stream()
                .toList();
        List<DictByTypePO> dict = dictService.findDictByTypes(typeCodes);
        final List<DictDTO> dictDTOS = dictConvert.byTypePOs2DTOs(dict);
        final Map<String, List<com.jwipc.sys.dto.DictDTO>> map = dictDTOS.stream()
                .collect(Collectors.groupingBy(DictDTO::getTypeCode));
        return map;
    }


}