package pwc.taxtech.atms.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.POIUtil;
import pwc.taxtech.atms.common.message.ErrorMessage;
import pwc.taxtech.atms.common.message.TemplateMessage;
import pwc.taxtech.atms.constant.Constant;
import pwc.taxtech.atms.constant.enums.CellDataSourceType;
import pwc.taxtech.atms.constant.enums.TemplateGroupType;
import pwc.taxtech.atms.dao.CellTemplateConfigDao;
import pwc.taxtech.atms.dao.CellTemplateConfigMapper;
import pwc.taxtech.atms.dao.CellTemplateDao;
import pwc.taxtech.atms.dao.CellTemplateMapper;
import pwc.taxtech.atms.dao.TemplateDao;
import pwc.taxtech.atms.dao.TemplateGroupDao;
import pwc.taxtech.atms.dao.TemplateGroupMapper;
import pwc.taxtech.atms.dao.TemplateMapper;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.TemplateGroupDto;
import pwc.taxtech.atms.entity.CellTemplate;
import pwc.taxtech.atms.entity.CellTemplateConfig;
import pwc.taxtech.atms.entity.CellTemplateConfigExample;
import pwc.taxtech.atms.entity.CellTemplateExample;
import pwc.taxtech.atms.entity.Template;
import pwc.taxtech.atms.entity.TemplateExample;
import pwc.taxtech.atms.entity.TemplateGroup;
import pwc.taxtech.atms.entity.TemplateGroupExample;
import pwc.taxtech.atms.exception.ServiceException;
import pwc.taxtech.atms.vat.dao.PeriodDataSourceMapper;
import pwc.taxtech.atms.vat.entity.PeriodDataSource;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TemplateGroupServiceImpl extends AbstractService {
    @Autowired
    private HttpFileService httpFileService;
    @Autowired
    private TemplateGroupDao templateGroupDao;
    @Autowired
    private TemplateGroupMapper templateGroupMapper;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private TemplateDao templateDao;
    @Autowired
    private CellTemplateMapper cellTemplateMapper;
    @Autowired
    private CellTemplateDao cellTemplateDao;
    @Autowired
    private CellTemplateConfigMapper cellTemplateConfigMapper;
    @Autowired
    private CellTemplateConfigDao cellTemplateConfigDao;
    @Autowired
    private PeriodDataSourceMapper periodDataSourceMapper;

    public List<TemplateGroupDto> get() {
        List<TemplateGroup> templateGroups = templateGroupMapper.selectByExample(new TemplateGroupExample());
        List<TemplateGroupDto> templateGroupDtos = new ArrayList<>();
        for (TemplateGroup templateGroup : templateGroups) {
            TemplateGroupDto templateGroupDto = new TemplateGroupDto();
            CommonUtils.copyProperties(templateGroup, templateGroupDto);
            templateGroupDtos.add(templateGroupDto);
        }
        return templateGroupDtos;
    }

    public List<TemplateGroupDto> get(int serviceTypeId, Integer taxPayType, String industryId) {
        TemplateGroupExample example = new TemplateGroupExample();

        TemplateGroupExample.Criteria criteria = example.createCriteria();

        criteria.andServiceTypeIdEqualTo(String.valueOf(serviceTypeId)).andGroupTypeEqualTo(TemplateGroupType.TaxReturn.getCode());

        if (taxPayType != null) {
            criteria.andPayTaxTypeEqualTo(TemplateGroupType.TaxReturn.getCode());
        }

        List<TemplateGroup> templateGroups = templateGroupMapper.selectByExample(example);
        List<TemplateGroupDto> templateGroupDtos = new ArrayList<>();
        for (TemplateGroup templateGroup : templateGroups) {
            TemplateGroupDto dto = new TemplateGroupDto();
            CommonUtils.copyProperties(templateGroup, dto);
            templateGroupDtos.add(dto);
        }
        return templateGroupDtos;
    }

    public OperationResultDto<Object> updateTemplateGroupName(TemplateGroupDto templateGroupDto) {
        TemplateGroup entity = templateGroupMapper.selectByPrimaryKey(Long.parseLong(templateGroupDto.getId()));
        TemplateGroupExample example = new TemplateGroupExample();
        example.createCriteria().andNameEqualTo(templateGroupDto.getName()).andIdNotEqualTo(Long.parseLong(templateGroupDto.getId())).andServiceTypeIdEqualTo(entity.getServiceTypeId()).andIndustryIdsEqualTo(entity.getIndustryIds()).andPayTaxTypeEqualTo(entity.getPayTaxType());
        List<TemplateGroup> templateGroups = templateGroupMapper.selectByExample(example);
        if (!templateGroups.isEmpty()) {
            OperationResultDto<Object> result = new OperationResultDto<>();
            result.setResult(false);
            result.setResultMsg(TemplateGroupMessage.TEMPLATE_GROUP_NAME_EXIST);
        }
        entity.setName(templateGroupDto.getName());
        templateGroupMapper.updateByPrimaryKey(entity);
        OperationResultDto<Object> result = new OperationResultDto<>();
        result.setResult(true);
        return result;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public OperationResultDto<Object> deleteTemplateGroup(TemplateGroupDto templateGroupDto) {
        OperationResultDto<Object> result = new OperationResultDto<>();
        TemplateGroup templateGroupDb = templateGroupMapper.selectByPrimaryKey(Long.parseLong(templateGroupDto.getId()));

        if (templateGroupDb.getIsSystemType()) {
            result.setResult(false);
            result.setResultMsg(TemplateGroupMessage.SYSTEM_TYPE_CANNOT_DELETE);
            return result;
        }

        List<String> userOranizationNameList = organizationServiceTemplateGroupMapper.getOrgnizationServiceTemplateGroupOrgNames(Long.parseLong(templateGroupDto.getId()));
        if (userOranizationNameList != null && !userOranizationNameList.isEmpty()) {
            result.setResult(false);
            result.setResultMsg(TemplateGroupMessage.ORGANIZATION_USED_TEMPLATE_GROUP);
            return result;
        }

        List<Template> allTemplateDbList = templateMapper.selectByExample(new TemplateExample());
        List<Template> templateDbList = allTemplateDbList.stream().filter(a -> a.getTemplateGroupId().equals(templateGroupDb.getId())).collect(Collectors.toList());
        List<String> pathList = new ArrayList<>();

        for (Template templateDb : templateDbList) {
            boolean anySameCodeExists = allTemplateDbList.stream().anyMatch(a -> a.getCode() == templateDb.getCode() && a.getName() == templateDb.getCode());

            if (!anySameCodeExists) {
                pathList.add((templateDb.getPath()));
            }
            deleteTemplate(templateDb);
        }
        templateGroupMapper.deleteByPrimaryKey(templateGroupDb.getId());

        result.setResult(true);
        result.setData(pathList);
        return result;
    }

    private void deleteTemplate(Template templateDb) {
        cellTemplateConfigMapper.deleteCellTemplateConfigByCellTemplate(templateDb.getId());
        keyValueReferenceMapper.deleteKeyValueReferenceByCellTemplate(templateDb.getId());
        CellTemplateExample example = new CellTemplateExample();
        example.createCriteria().andReportTemplateIdEqualTo(templateDb.getId());
        cellTemplateMapper.deleteByExample(example);
    }

    public class TemplateGroupMessage {
        static final String TEMPLATE_GROUP_NAME_EXIST = "TemplateGroupNameExist";
        static final String SYSTEM_TYPE_CANNOT_DELETE = "SystemTypeCannotDelete";
        static final String ORGANIZATION_USED_TEMPLATE_GROUP = "OrganizationUsedTemplateGroup";
    }

    public List<String> getSheetNameList(MultipartFile file) {
        try {
            Workbook workbook = WorkbookFactory.create(file.getInputStream());
            List<String> nameList = Lists.newArrayList();
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                nameList.add(workbook.getSheetName(i));
            }
            return nameList;
        } catch (Exception e) {
            logger.error("getSheetNameList error.", e);
        }
        return Collections.emptyList();
    }

    @Transactional
    public void importTemplateGroupExcelFile(MultipartFile file, boolean allowManual, TemplateGroupDto templateGroupDto) throws ServiceException {
        List<String> sheetNameList = templateGroupDto.getSheetNameList();
        if (CollectionUtils.isEmpty(sheetNameList)) {
            throw new ServiceException(ErrorMessage.NoSelectSheet);
        }
        try {
            List<TemplateGroup> groupList = templateGroupDao.getByGroupName(templateGroupDto.getName());
            if (CollectionUtils.isNotEmpty(groupList)) {
                throw new ServiceException(TemplateMessage.TemplateGroupNameExist);
            }
            InputStream inputStream = file.getInputStream();
            String fileName = file.getOriginalFilename();
            Workbook workbook = WorkbookFactory.create(inputStream);
            List<Template> filePathList = Lists.newArrayList();
            Long templateGroupId = distributedIdService.nextId();
            Date now = new Date();
            TemplateGroup templateGroup = new TemplateGroup();
            CommonUtils.copyProperties(templateGroupDto, templateGroup);
            templateGroup.setId(templateGroupId);
            templateGroup.setGroupType(1);//todo 整理枚举
            templateGroup.setCopyFrom(0L);
            templateGroup.setIsSystemType(false);
            templateGroup.setUpdateTime(now);
            templateGroupMapper.insertSelective(templateGroup);
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                String sheetName = workbook.getSheetName(i);
                if(!sheetNameList.contains(sheetName)){
                    continue;
                }
                String newName = sheetName + CommonUtils.getUUID() + POIUtil.getFileSuffix(fileName).get();
                Sheet sheet = workbook.getSheetAt(i);
                Optional<Workbook> optional = POIUtil.cloneNewSheet(sheet, fileName);
                if (!optional.isPresent()) {
                    throw new ServiceException(ErrorMessage.SystemError);
                }
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                optional.get().write(bos);
                String tmpPath = httpFileService.uploadTemplate(newName, file);
                String[] arr = sheetName.split("_");
                String name = arr.length >= 2 ? arr[1] : arr[0];
                Template template = new Template();
                template.setCode(arr[0]);
                template.setCreateTime(now);
                template.setId(distributedIdService.nextId());
                template.setIsActiveAssociation(true);
                template.setIsSystemType(false);
                template.setName(name);
                template.setOrderIndex(i + 1);
                template.setPath(tmpPath);
//                template.setReportType(tmpPath);
                template.setTemplateGroupId(templateGroupId);
                filePathList.add(template);
                templateMapper.insertSelective(template);
                List<CellTemplate> cellTemplateList = Lists.newArrayList();
                List<CellTemplateConfig> cellTemplateConfigList = Lists.newArrayList();
                List<PeriodDataSource> periodDataSourceList = Lists.newArrayList();
                for (int r = sheet.getFirstRowNum(); r <= sheet.getLastRowNum(); r++) {
                    Row row = sheet.getRow(r);
                    for (int c = row.getFirstCellNum(); c <= row.getLastCellNum(); c++) {
                        Cell cell = row.getCell(c);
                        if (cell == null) {
                            continue;//todo cell == null 如何处理
                        }
                        CellTemplate cellTemplate = new CellTemplate();
                        cellTemplate.setColumnIndex(c);
                        cellTemplate.setCreateTime(now);
                        cellTemplate.setUpdateTime(now);
                        cellTemplate.setRowIndex(r);
                        cellTemplate.setRowName(StringUtils.EMPTY);
                        cellTemplate.setColumnName(StringUtils.EMPTY);
                        cellTemplate.setComment(StringUtils.EMPTY);
                        cellTemplate.setCopyFromId(0L);
                        cellTemplate.setCreateBy("Admin");
                        cellTemplate.setUpdateBy("Admin");
                        cellTemplate.setDataType(0);
                        cellTemplate.setReportTemplateId(template.getId());
                        cellTemplate.setId(distributedIdService.nextId());
                        if (cell.getCellComment() != null) {
                            cellTemplate.setComment(cell.getCellComment().getString().getString());
                        }
                        cellTemplate.setIsReadOnly(cell.getCellStyle().getLocked());
                        cellTemplateList.add(cellTemplate);
                        //todo: 这里没有Config数据只有在上传模板以后,在界面里面可以配置公式
                        if (!cell.getCellStyle().getLocked() && hasKeyIn(cell)) {
                            cell.setCellValue(StringUtils.EMPTY);
                            if(allowManual){
                                addManualConfig(cellTemplate, template, cell, now, cellTemplateConfigList);
                            }
                        }
                        if(!cell.getCellStyle().getLocked() && StringUtils.isNotBlank(POIUtil.getCellFormulaString(cell))) {
                            CellTemplateConfig config = new CellTemplateConfig();
                            config.setId(distributedIdService.nextId());
                            config.setCellTemplateId(cellTemplate.getId());
                            config.setReportTemplateId(template.getId());
                            config.setDataSourceType(CellDataSourceType.Formula.getCode());//todo 枚举
                            config.setFormula(POIUtil.getCellFormulaString(cell));
//                        config.setFormula(cell.getCellFormula());
                            config.setFormulaDataSource("报表数据"); //todo KV相关
                            config.setUpdateTime(now);
                            config.setUpdateBy(authUserHelper.getCurrentUserId());
                            cellTemplateConfigList.add(config);
                            if (allowManual) {
                                addManualConfig(cellTemplate, template, cell, now, cellTemplateConfigList);
                            }

                            PeriodDataSource pds = new PeriodDataSource();
                            pds.setAmount(BigDecimal.ZERO);
                            pds.setUpdateBy("Admin");
                            pds.setUpdateTime(new Date());
                            pds.setId(distributedIdService.nextId());
                            pds.setCreateTime(new Date());
                            pds.setCellTemplateId(cellTemplate.getId());
                            pds.setCreateBy("Admin");
                            pds.setDescription(" ");
                            pds.setName("ReportDataSource");
                            Calendar cal = Calendar.getInstance();
                            pds.setPeriod(cal.get(Calendar.MONTH) + 1);
                            pds.setType(5);
                            pds.setColumnIndex(cell.getColumnIndex());
                            pds.setRowIndex(cell.getRowIndex());
                            periodDataSourceList.add(pds);
                        }
                    }
                }
                List<List<CellTemplate>> tmpList = CommonUtils.subListWithLen(cellTemplateList, CommonUtils.BATCH_NUM);
                tmpList.forEach(list -> cellTemplateMapper.batchInsert2(list));
                List<List<CellTemplateConfig>> tmpConfigList = CommonUtils.subListWithLen(cellTemplateConfigList, CommonUtils.BATCH_NUM);
                tmpConfigList.forEach(list -> cellTemplateConfigMapper.batchInsert(list));
                List<List<PeriodDataSource>> tmpPeriodList = CommonUtils.subListWithLen(periodDataSourceList, CommonUtils.BATCH_NUM);
                tmpPeriodList.forEach(list -> periodDataSourceMapper.batchInsert(list));
            }

        } catch (Exception e) {
            logger.error("importTemplateGroupExcelFile error.", e);
            throw new ServiceException(ErrorMessage.SystemError);
        }
    }

    @Transactional
    public void importTemplateExcelFile(MultipartFile file, boolean allowManual, Long templateGroupId, String reportType, String sheetList) throws ServiceException {
        if (null == file) {
            throw new ServiceException(ErrorMessage.NoFile);
        }
        try {
            if (StringUtils.isBlank(sheetList)) {
                throw new ServiceException(ErrorMessage.NoSelectSheet);
            }
            List<String> sheetNameList = JSON.parseArray(sheetList, String.class);
            if (CollectionUtils.isEmpty(sheetNameList)) {
                throw new ServiceException(ErrorMessage.NoSelectSheet);
            }
            InputStream inputStream = file.getInputStream();
            String fileName = file.getOriginalFilename();
            Workbook workbook = WorkbookFactory.create(inputStream);
            List<Template> filePathList = Lists.newArrayList();
            Date now = new Date();
            TemplateExample t = new TemplateExample();
            t.createCriteria().andTemplateGroupIdEqualTo(templateGroupId);
            int length = templateMapper.selectByExample(t).size();
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                String sheetName = workbook.getSheetName(i);
                if(!sheetNameList.contains(sheetName)){
                    continue;
                }
                String newName = sheetName + CommonUtils.getUUID() + POIUtil.getFileSuffix(fileName).get();
                Sheet sheet = workbook.getSheetAt(i);
                Optional<Workbook> optional = POIUtil.cloneNewSheet(sheet, fileName);
                if (!optional.isPresent()) {
                    throw new ServiceException(ErrorMessage.SystemError);
                }
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                Workbook wtemp = optional.get();
                Sheet temp = wtemp.getSheetAt(0);
                for(int j = temp.getFirstRowNum(); j < temp.getLastRowNum(); j ++){
                    Row row = temp.getRow(j);
                    for(int k = row.getFirstCellNum(); k < row.getLastCellNum(); k++){
                        Cell cell = row.getCell(k);
                        cell.setCellType(CellType.STRING);
                        if(!cell.getCellStyle().getLocked()  && "${KeyIn}".equalsIgnoreCase(cell.getStringCellValue())){
                            cell.setCellValue("");
                        }
                    }
                }
                wtemp.write(bos);
                String tmpPath = httpFileService.uploadTemplate(newName, file);
                String[] arr = sheetName.split("_");
                String name = arr.length >= 2 ? arr[1] : arr[0];
                Template template = new Template();
                template.setCode(arr[0]);
                template.setCreateTime(now);
                template.setId(distributedIdService.nextId());
                template.setIsActiveAssociation(true);
                template.setIsSystemType(false);
                template.setName(name);
                template.setOrderIndex(i + length);
                template.setPath(tmpPath);
                template.setReportType(StringUtils.isBlank(reportType) ? null : Integer.valueOf(reportType));
                template.setTemplateGroupId(templateGroupId);
                filePathList.add(template);
                templateMapper.insertSelective(template);
                List<CellTemplate> cellTemplateList = Lists.newArrayList();
                List<CellTemplateConfig> cellTemplateConfigList = Lists.newArrayList();
                List<PeriodDataSource> periodDataSourceList = Lists.newArrayList();
                for (int r = sheet.getFirstRowNum(); r <= sheet.getLastRowNum(); r++) {
                    Row row = sheet.getRow(r);
                    for (int c = row.getFirstCellNum(); c <= row.getLastCellNum(); c++) {
                        Cell cell = row.getCell(c);
                        if (cell == null) {
                            continue;//todo cell == null 如何处理
                        }
                        CellTemplate cellTemplate = new CellTemplate();
                        cellTemplate.setColumnIndex(c);
                        cellTemplate.setCreateTime(now);
                        cellTemplate.setUpdateTime(now);
                        cellTemplate.setRowIndex(r);
                        cellTemplate.setReportTemplateId(template.getId());
                        cellTemplate.setId(distributedIdService.nextId());
                        if (cell.getCellComment() != null) {
                            cellTemplate.setComment(cell.getCellComment().getString().getString());
                        }
                        cellTemplate.setIsReadOnly(cell.getCellStyle().getLocked() ? true : false);
                        cellTemplateList.add(cellTemplate);
                        //todo: 这里没有Config数据只有在上传模板以后,在界面里面可以配置公式
                        if (!cell.getCellStyle().getLocked() && hasKeyIn(cell)) {
                            cell.setCellValue(StringUtils.EMPTY);
                            if(allowManual){
                                addManualConfig(cellTemplate, template, cell, now, cellTemplateConfigList);
                            }
                        }
                        if(!cell.getCellStyle().getLocked() && StringUtils.isNotBlank(POIUtil.getCellFormulaString(cell))) {
                            CellTemplateConfig config = new CellTemplateConfig();
                            config.setId(distributedIdService.nextId());
                            config.setCellTemplateId(cellTemplate.getId());
                            config.setReportTemplateId(template.getId());
                            config.setDataSourceType(1);//todo 枚举
                            config.setFormula(POIUtil.getCellFormulaString(cell));
//                        config.setFormula(cell.getCellFormula());
                            config.setFormulaDataSource("报表数据"); //todo KV相关
                            config.setUpdateTime(now);
                            config.setUpdateBy(authUserHelper.getCurrentUserId());
                            cellTemplateConfigList.add(config);
                            //noinspection Duplicates
                            if (allowManual) {
                                addManualConfig(cellTemplate, template, cell, now, cellTemplateConfigList);
                            }
                            PeriodDataSource pds = new PeriodDataSource();
                            pds.setAmount(BigDecimal.ZERO);
                            pds.setUpdateBy("Admin");
                            pds.setUpdateTime(new Date());
                            pds.setId(distributedIdService.nextId());
                            pds.setCreateTime(new Date());
                            pds.setCellTemplateId(cellTemplate.getId());
                            pds.setCreateBy("Admin");
                            pds.setDescription(" ");
                            pds.setName("ReportDataSource");
                            Calendar cal = Calendar.getInstance();
                            pds.setPeriod(cal.get(Calendar.MONTH) + 1);
                            pds.setType(5);
                            pds.setColumnIndex(cell.getColumnIndex());
                            pds.setRowIndex(cell.getRowIndex());
                            periodDataSourceList.add(pds);
                        }
                    }
                }
                List<List<CellTemplate>> tmpList = CommonUtils.subListWithLen(cellTemplateList, CommonUtils.BATCH_NUM);
//                tmpList.forEach(list -> cellTemplateMapper.batchInsert2(list));
                tmpList.forEach(list -> cellTemplateDao.batchInsert(list));//todo 批量插入优化
                List<List<CellTemplateConfig>> tmpConfigList = CommonUtils.subListWithLen(cellTemplateConfigList, CommonUtils.BATCH_NUM);
                tmpConfigList.forEach(list -> cellTemplateConfigDao.batchInsert(list));
                List<List<PeriodDataSource>> tmpPeriodList = CommonUtils.subListWithLen(periodDataSourceList, CommonUtils.BATCH_NUM);
                tmpPeriodList.forEach(list -> periodDataSourceMapper.batchInsert(list));
            }
        } catch (Exception e) {
            logger.error("importTemplateExcelFile error.", e);
            throw new ServiceException(ErrorMessage.SystemError);
        }
    }

    @Transactional
    public void addTemplateGroup(TemplateGroupDto templateGroupDto) throws ServiceException {
        List<TemplateGroup> groupList = templateGroupDao.getByGroupName(templateGroupDto.getName());
        if (CollectionUtils.isNotEmpty(groupList)) {
            throw new ServiceException(TemplateMessage.TemplateGroupNameExist);
        }
        try {
            String uid = authUserHelper.getCurrentUserId();
            TemplateGroup templateGroup = templateGroupMapper.selectByPrimaryKey(Long.parseLong(templateGroupDto.getCopyFrom()));
            Long newGroupId = distributedIdService.nextId();
            Long groupId = templateGroup.getId();
            Date now = new Date();
            templateGroup.setCopyFrom(groupId);
            templateGroup.setId(newGroupId);
            templateGroup.setCreateTime(now);
            templateGroup.setUpdateTime(now);
            templateGroup.setName(templateGroupDto.getName());
            templateGroupMapper.insertSelective(templateGroup);
            List<Template> templateList = templateDao.getByGroupId(groupId);
            templateList.stream().forEach(item -> {
                Long itemId = item.getId();
                Long newItemId = distributedIdService.nextId();
                item.setId(newItemId);
                item.setTemplateGroupId(newGroupId);
                item.setCreateTime(now);
                item.setUpdateTime(now);
                templateMapper.insertSelective(item);
                List<CellTemplate> cellTemplateList = cellTemplateDao.getByTemplateId(itemId);
                Map<Long, Long> idMapper = Maps.newHashMap();
                List<List<CellTemplate>> tmpList = CommonUtils.subListWithLen(cellTemplateList.stream().map(cell -> {
                    Long cellId = cell.getId();
                    Long newCellId = distributedIdService.nextId();
                    cell.setCopyFromId(cellId);
                    cell.setId(newCellId);
                    cell.setReportTemplateId(newItemId);
                    cell.setCreateTime(now);
                    cell.setUpdateTime(now);
                    idMapper.put(cellId, newCellId);
                    return cell;
                }).collect(Collectors.toList()), CommonUtils.BATCH_NUM);
                tmpList.forEach(list -> cellTemplateMapper.batchInsert2(list));

                List<CellTemplateConfig> configList = getByTemplateId(itemId);
                List<List<CellTemplateConfig>> tmpConfigList = CommonUtils.subListWithLen(configList.stream().map(cell -> {
                    Long newCellId = distributedIdService.nextId();
                    cell.setCreateBy(uid);
                    cell.setUpdateBy(uid);
                    cell.setId(newCellId);
                    cell.setReportTemplateId(newItemId);
                    cell.setCellTemplateId(idMapper.get(cell.getCellTemplateId()));
                    cell.setCreateTime(now);
                    cell.setUpdateTime(now);
                    return cell;
                }).collect(Collectors.toList()), CommonUtils.BATCH_NUM);
                tmpConfigList.forEach(list -> cellTemplateConfigMapper.batchInsert(list));
            });
        } catch (Exception e) {
            logger.error("addTemplateGroup error.", e);
            throw new ServiceException(ErrorMessage.SystemError);
        }

    }

    @Transactional
    public void addTemplateGroupWithoutTemplate(TemplateGroupDto templateGroupDto) throws ServiceException {
        List<TemplateGroup> groupList = templateGroupDao.getByGroupName(templateGroupDto.getName());
        if (CollectionUtils.isNotEmpty(groupList)) {
            throw new ServiceException(TemplateMessage.TemplateGroupNameExist);
        }
        try {
            TemplateGroup templateGroup=new TemplateGroup();
            CommonUtils.copyProperties(templateGroupDto,templateGroup);
            Long newGroupId = distributedIdService.nextId();
            Date now = new Date();
            templateGroup.setId(newGroupId);
            templateGroup.setCreateTime(now);
            templateGroup.setUpdateTime(now);
            templateGroup.setName(templateGroupDto.getName());
            templateGroupMapper.insertSelective(templateGroup);
        } catch (Exception e) {
            logger.error("addTemplateGroupWithoutTemplate error.", e);
            throw new ServiceException(ErrorMessage.SystemError);
        }
    }

    private List<CellTemplateConfig> getByTemplateId(Long id) {
        CellTemplateConfigExample example = new CellTemplateConfigExample();
        CellTemplateConfigExample.Criteria criteria = example.createCriteria();
        criteria.andReportTemplateIdEqualTo(id);
        return cellTemplateConfigMapper.selectByExample(example);
    }

    /**
     * 替换占位符
     * @param cell cell
     * @return Boolean
     */
    private Boolean hasKeyIn(Cell cell) {
        if (null == cell) {
            return false;
        }
        CellType cellType = cell.getCellTypeEnum();
        if (!CellType.STRING.equals(cellType)) {
            return false;
        }
        String v = cell.getStringCellValue();
        if (StringUtils.isBlank(v)) {
            return false;
        }
        return StringUtils.equals(v, Constant.ReplaceKeyword.KEY_IN);
    }

    /**
     * 添加手工数据源
     */
    private void addManualConfig(CellTemplate cellTemplate, Template template, Cell cell, Date now, List<CellTemplateConfig> list) {
        CellTemplateConfig configManual = new CellTemplateConfig();
        configManual.setId(distributedIdService.nextId());
        configManual.setCellTemplateId(cellTemplate.getId());
        configManual.setReportTemplateId(template.getId());
        configManual.setDataSourceType(CellDataSourceType.KeyIn.getCode());
        configManual.setFormula(POIUtil.getCellFormulaString(cell));
//        config.setFormula(cell.getCellFormula());
//        configManual.setFormulaDataSource("报表数据"); //todo KV相关
        configManual.setUpdateTime(now);
        configManual.setUpdateBy(authUserHelper.getCurrentUserId());
        list.add(configManual);
    }

}