package com.dsk.cscec.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsk.common.excel.ExcelUtils;
import com.dsk.common.utils.StringUtils;
import com.dsk.cscec.constant.CbProjectConstants;
import com.dsk.cscec.domain.CbProjectExpenseSummary;
import com.dsk.cscec.domain.CbProjectFile;
import com.dsk.cscec.domain.CbProjectRecord;
import com.dsk.cscec.mapper.CbProjectExpenseSummaryMapper;
import com.dsk.cscec.mapper.CbProjectFileMapper;
import com.dsk.cscec.mapper.CbProjectRecordMapper;
import com.dsk.cscec.service.CbProjectExpenseSummaryService;
import com.dsk.system.service.ISysOssService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CbProjectExpenseSummaryServiceImpl extends ServiceImpl<CbProjectExpenseSummaryMapper, CbProjectExpenseSummary> implements CbProjectExpenseSummaryService {
    @Resource
    private CbProjectExpenseSummaryMapper baseMapper;
    @Resource
    private CbProjectRecordMapper projectRecordMapper;
    @Resource
    private CbProjectFileMapper projectFileMapper;
    @Resource
    private ISysOssService ossService;
    @Resource
    private TransactionTemplate transactionTemplate;

    /**
     * 现场经费汇总数据解析
     *
     * @param projectId 项目ID
     * @param cbStage   成本阶段
     * @param username  用户名
     */
    @Override
    @Async
    public void parseSceneExpenseSummaryData(Long projectId, Integer cbStage, String username) throws Exception {
        //查找该项目下所有相关文件
        List<CbProjectFile> projectFileList = projectFileMapper.selectAnalysisList(projectId, CbProjectConstants.CB_TYPE_SCENE_EXPENSE, cbStage);

        //待解析文件
        List<CbProjectFile> waitParseList = new ArrayList<>();
        //提取现场经费汇总文件,原则上该文件仅有1个
        projectFileList.forEach(projectFile -> {
            if (CbProjectConstants.CB_TYPE_SCENE_EXPENSE_NAME.equals(projectFile.getFileName().substring(0, projectFile.getFileName().lastIndexOf(".")))) {
                //待解析文件
                waitParseList.add(projectFile);
            }
        });

        //处理待解析文件
        for (CbProjectFile projectFile : waitParseList) {
            if (ObjectUtil.isNull(projectFile)) {
                continue;
            }

            //文件下载
            InputStream inputStream = ossService.downFileIO(projectFile.getFileOssId());
            if (ObjectUtil.isNull(inputStream)) {
                projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                log.error("FileId:" + projectFile.getId() + ",文件数据不存在");
                projectFile.setFailRemark("文件数据不存在");
                projectFileMapper.updateById(projectFile);
                continue;
            }
            //解析数据
            List<CbProjectExpenseSummary> importList = new ExcelUtils<>(CbProjectExpenseSummary.class).importExcelAllSheet(inputStream, 0);
            if (importList.isEmpty()) {
                projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                log.error("FileId:" + projectFile.getId() + ",表格中不存在待导入数据");
                projectFile.setFailRemark("表格中不存在待导入数据!");
                projectFileMapper.updateById(projectFile);
                continue;
            }

            //筛选有效数据
            List<CbProjectExpenseSummary> summaryList = importList.stream().parallel()
                    //筛选名称列不为空数据
                    .filter(item -> StringUtils.isNotBlank(item.getExpenseName()))
                    .peek(item -> {
                        item.setProjectId(projectId);
                        item.setProjectFileId(projectFile.getId());
                        item.setCbStage(projectFile.getCbStage());
                        item.setDataType(CbProjectConstants.CB_TYPE_SCENE_EXPENSE);
                        item.setCreateBy(username);
                        item.setCreateTime(new Date());
                    })
                    .collect(Collectors.toList());
            if (summaryList.size() != importList.size()) {
                projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                log.error("FileId:" + projectFile.getId() + ",表格中\"名称\"列存在空数据!");
                projectFile.setFailRemark("表格中\"名称\"列存在空数据");
                projectFileMapper.updateById(projectFile);
                continue;
            }
            transactionTemplate.execute(status -> {
                try {
                    //批量插入数据
                    CbProjectExpenseSummaryServiceImpl impl = new CbProjectExpenseSummaryServiceImpl();
                    Assert.isTrue(impl.saveBatch(summaryList), "数据插入失败");
                    //更新文件状态
                    projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
                    //场景:若第一次解析失败了,用户未删除失败的文件,又解析一次,这时解析成功了,因此将失败备注置空
                    projectFile.setFailRemark(null);
                    Assert.isTrue(projectFileMapper.updateById(projectFile) > 0, "解析成功后文件状态更新失败");
                } catch (Exception e) {
                    status.setRollbackOnly();
                    projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                    projectFile.setFailRemark(e.getMessage());
                    projectFileMapper.updateById(projectFile);
                }
                return Boolean.TRUE;
            });
        }
    }

    /**
     * 获取现场经费汇总数据
     *
     * @param projectId 项目ID
     * @return 现场经费汇总数据
     */
    @Override
    public List<CbProjectExpenseSummary> getCbSceneExpenseSummaryData(Long projectId) {
        //校验项目是否存在
        this.checkProjectExist(projectId);

        return baseMapper.selectList(new LambdaQueryWrapper<CbProjectExpenseSummary>()
                .eq(CbProjectExpenseSummary::getProjectId, projectId)
                .eq(CbProjectExpenseSummary::getDataType, CbProjectConstants.CB_TYPE_SCENE_EXPENSE));
    }

    @Override
    public List<CbProjectExpenseSummary> queryCbSceneExpenseSummaryDataByType(Long projectId, Integer dataType) {
        //校验项目是否存在
        this.checkProjectExist(projectId);

        return baseMapper.selectList(new LambdaQueryWrapper<CbProjectExpenseSummary>()
                .eq(CbProjectExpenseSummary::getProjectId, projectId)
                .eq(CbProjectExpenseSummary::getDataType, dataType));
    }

    /**
     * 校验项目是否存在
     *
     * @param projectId 项目ID
     * @return 项目实体
     */
    private CbProjectRecord checkProjectExist(Long projectId) {
        CbProjectRecord projectRecord = projectRecordMapper.selectById(projectId);
        Assert.notNull(projectRecord, "该项目不存在");
        return projectRecord;
    }
}
