package com.dsk.cscec.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsk.common.exception.ServiceException;
import com.dsk.cscec.constant.CbProjectConstants;
import com.dsk.cscec.domain.*;
import com.dsk.cscec.domain.bo.AddProjectFileUploadBo;
import com.dsk.cscec.domain.bo.DeleteCbProjectFileBo;
import com.dsk.cscec.domain.vo.QueryProjectFileUploadDetailVo;
import com.dsk.cscec.mapper.CbProjectFileMapper;
import com.dsk.cscec.mapper.CbProjectRecordMapper;
import com.dsk.cscec.service.*;
import com.dsk.system.domain.vo.SysOssVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 项目成本文件表(CbProjectFile)表服务实现类
 *
 * @author sxk
 * @since 2024-02-05 14:01:06
 */
@Service("cbProjectFileService")
public class CbProjectFileServiceImpl extends ServiceImpl<CbProjectFileMapper, CbProjectFile> implements CbProjectFileService {
    @Resource
    private CbProjectFileMapper baseMapper;
    @Resource
    private CbProjectRecordMapper projectRecordMapper;
    @Resource
    private CbDirectExpenseService directExpenseService;
    @Resource
    private ICbQuantitySummaryService quantitySummaryService;
    @Resource
    private ICbQuantitySummaryActualService quantitySummaryActualService;
    @Resource
    private ICbCostMeasureService costMeasureService;
    @Resource
    private ICbCostMeasureActualService costMeasureActualActualService;
    @Resource
    private CbProjectOtherService projectOtherService;
    @Resource
    private CbSceneExpenseChildrenService sceneExpenseChildrenService;
    @Resource
    private CbProjectExpenseSummaryService projectExpenseSummaryService;
    @Resource
    private CbSummaryService summaryService;
    @Resource
    private CbSummaryActualService summaryActualService;
    @Resource
    private CbSummaryActualLockService summaryActualLockService;

    /**
     * 校验同一成本类型下是否存在相同文件
     *
     * @param fileUploadBo 上传信息
     */
    @Override
    public Boolean checkProjectFileExist(AddProjectFileUploadBo fileUploadBo) {
        String filename = fileUploadBo.getFile().getOriginalFilename();
        assert filename != null;
        baseMapper.selectList(new LambdaQueryWrapper<CbProjectFile>()
                .eq(CbProjectFile::getProjectId, fileUploadBo.getProjectId())
                .eq(CbProjectFile::getCbType, fileUploadBo.getCbType())).forEach(projectFile -> {
            //仅对比文件名,不考虑文件格式
            Assert.isFalse(projectFile.getFileName().substring(0, projectFile.getFileName().lastIndexOf(".")).equals(filename.substring(0, filename.lastIndexOf(".")))
                    , "当前成本类型下存在同名文件,请重新上传");
        });
        return true;
    }

    /**
     * 添加项目上传文件记录
     *
     * @param fileUploadBo 上传信息
     * @param oss          oss信息
     * @return 文件记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CbProjectFile addProjectFile(AddProjectFileUploadBo fileUploadBo, SysOssVo oss) {
        //校验项目是否存在
        CbProjectRecord projectRecord = this.checkProjectExist(fileUploadBo.getProjectId());

        CbProjectFile projectFile = BeanUtil.toBean(fileUploadBo, CbProjectFile.class);
        projectFile.setCbStage(projectRecord.getCbStage());
        projectFile.setFileName(oss.getOriginalName());
        projectFile.setFileOssId(oss.getOssId());
        projectFile.setFileOssUrl(oss.getUrl());
        //项目文件状态:准备中
        projectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PREPARING);
        baseMapper.insert(projectFile);
        return projectFile;
    }

    /**
     * 删除项目台账文件及对应数据
     *
     * @param deleteBo 待删除文件信息
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteProjectFile(DeleteCbProjectFileBo deleteBo) {
        Long fileId = deleteBo.getFileId();
        //查询待删除文件
        CbProjectFile file = baseMapper.selectById(fileId);
        //不允许删除解析中的文件
        Integer fileParseStatus = file.getFileParseStatus();
        Assert.isFalse(fileParseStatus.equals(CbProjectConstants.PROJECT_FILE_STATUS_PARSING),
                "文件正在解析中,不允许删除");

        //解析成功、解析失败的文件需要删除对应的导入数据和每月成本数据
        if (fileParseStatus.equals(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS) ||
                fileParseStatus.equals(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL)) {
            switch (deleteBo.getCbType()) {
                case CbProjectConstants.CB_TYPE_DIRECT_EXPENSE:
                    //直接费没有每月成本,所以直接删除导入数据即可
                    Assert.isTrue(directExpenseService.removeBatchByIds(directExpenseService.list(new LambdaQueryWrapper<CbDirectExpense>()
                            .eq(CbDirectExpense::getProjectFileId, file.getId()))), "直接费成本数据删除失败");
                    break;
                case CbProjectConstants.CB_TYPE_QUANTITY_SUMMARY:
                    //工料汇总
                    List<CbQuantitySummary> quantitySummaryList = quantitySummaryService.list(new LambdaQueryWrapper<CbQuantitySummary>()
                            .eq(CbQuantitySummary::getCbProjectFileId, file.getId()));
                    //删除每月成本数据(关联导入数据主键)
                    quantitySummaryActualService.removeBatchByIds(quantitySummaryActualService.list(new LambdaQueryWrapper<CbQuantitySummaryActual>()
                            .in(CbQuantitySummaryActual::getCbQuantitySummaryId, quantitySummaryList.stream().map(CbQuantitySummary::getId).collect(Collectors.toList()))));
                    //删除导入数据(关联文件ID)
                    quantitySummaryService.removeBatchByIds(quantitySummaryList);
                    break;
                case CbProjectConstants.CB_TYPE_MEASURE_PROJECT:
                    //措施项目
                    List<CbCostMeasure> costMeasureList = costMeasureService.list(new LambdaQueryWrapper<CbCostMeasure>()
                            .eq(CbCostMeasure::getProjectFileId, fileId));
                    //删除每月成本数据(关联导入数据主键)
                    costMeasureActualActualService.removeBatchByIds(costMeasureActualActualService.list(new LambdaQueryWrapper<CbCostMeasureActual>()
                            .in(CbCostMeasureActual::getPlanMeasureId, costMeasureList.stream().map(CbCostMeasure::getId).collect(Collectors.toList()))));
                    //删除导入数据(关联文件ID)
                    costMeasureService.removeBatchByIds(costMeasureList);
                    //删除汇总数据
                    projectExpenseSummaryService.removeBatchByIds(projectExpenseSummaryService.list(new LambdaQueryWrapper<CbProjectExpenseSummary>()
                            .eq(CbProjectExpenseSummary::getProjectFileId, deleteBo.getFileId())));
                    break;
                case CbProjectConstants.CB_TYPE_OTHER_PROJECT:
                    //其他项目
                    projectOtherService.removeBatchByIds(projectOtherService.list(new LambdaQueryWrapper<CbProjectOther>()
                            .eq(CbProjectOther::getCbProjectFileId, deleteBo.getFileId())));
                    //删除汇总数据
                    projectExpenseSummaryService.removeBatchByIds(projectExpenseSummaryService.list(new LambdaQueryWrapper<CbProjectExpenseSummary>()
                            .eq(CbProjectExpenseSummary::getProjectFileId, deleteBo.getFileId())));
                    break;
                case CbProjectConstants.CB_TYPE_SCENE_EXPENSE:
                    //现场经费
                    //删除汇总数据(关联文件ID)
                    projectExpenseSummaryService.removeBatchByIds(projectExpenseSummaryService.list(new LambdaQueryWrapper<CbProjectExpenseSummary>()
                            .eq(CbProjectExpenseSummary::getProjectFileId, fileId)));
                    //汇总以外的数据(关联文件ID)
                    sceneExpenseChildrenService.removeBatchByIds(sceneExpenseChildrenService.list(new LambdaQueryWrapper<CbSceneExpenseChildren>()
                            .eq(CbSceneExpenseChildren::getProjectFileId, fileId)));
                    break;
                case CbProjectConstants.CB_TYPE_SUMMARY:
                    //成本汇总
                    //删除锁定数据(关联项目ID)
                    summaryActualLockService.removeBatchByIds(summaryActualLockService.list(new LambdaQueryWrapper<CbSummaryActualLock>()
                            .eq(CbSummaryActualLock::getProjectId, file.getProjectId())));
                    //删除每月成本数据(关联导入数据主键)
                    List<CbSummary> summaryList = summaryService.list(new LambdaQueryWrapper<CbSummary>()
                            .eq(CbSummary::getCbProjectFileId, fileId));
                    summaryActualService.removeBatchByIds(summaryActualService.list(new LambdaQueryWrapper<CbSummaryActual>()
                            .in(CbSummaryActual::getCbSummaryId, summaryList.stream().map(CbSummary::getId).collect(Collectors.toList()))));
                    //删除导入数据(关联文件ID)
                    summaryService.removeBatchByIds(summaryList);
                    break;
                default:
                    throw new ServiceException("成本类型错误");
            }
        }
        return baseMapper.deleteById(file);
    }

    /**
     * 获取项目文件上传详情
     *
     * @param projectId 项目ID
     * @return 文件列表
     */
    @Override
    public QueryProjectFileUploadDetailVo getProjectFileUploadDetail(Long projectId) {
        //校验项目是否存在
        this.checkProjectExist(projectId);

        List<CbProjectFile> projectFileList = baseMapper.selectList(new LambdaQueryWrapper<CbProjectFile>()
                .eq(CbProjectFile::getProjectId, projectId)
                //成本阶段
                //.eq(CbProjectFile::getCbStage, uploadDetailBo.getCbStage())
                //删除状态:否
                .eq(CbProjectFile::getDelFlag, CbProjectConstants.DELETE_FLAG_EXIST));

        QueryProjectFileUploadDetailVo draftDetailVo = new QueryProjectFileUploadDetailVo();
        draftDetailVo.setProjectId(projectId);
        if (projectFileList.isEmpty()) {
            return null;
        }

        //按照成本类型分类填充
        projectFileList.forEach(fileList -> {
            //TODO:此写法太丑陋,待优化
            if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_DIRECT_EXPENSE)) {
                //直接费成本
                draftDetailVo.getDirectExpense().add(fileList);
            } else if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_QUANTITY_SUMMARY)) {
                //工料汇总
                draftDetailVo.getQuantitySummary().add(fileList);
            } else if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_MEASURE_PROJECT)) {
                //措施项目
                draftDetailVo.getMeasureProject().add(fileList);
            } else if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_OTHER_PROJECT)) {
                //其他项目
                draftDetailVo.getOtherProject().add(fileList);
            } else if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_SCENE_EXPENSE)) {
                //现场经费
                draftDetailVo.getSceneExpense().add(fileList);
            } else if (Objects.equals(fileList.getCbType(), CbProjectConstants.CB_TYPE_SUMMARY)) {
                //成本汇总
                draftDetailVo.getCbSummary().add(fileList);
            }
        });
        return draftDetailVo;
    }

    @Override
    public List<CbProjectFile> selectAnalysisList(Long projectId, Integer cbType, Integer cbStage) {
        return baseMapper.selectAnalysisList(projectId, cbType, cbStage);
    }

    @Override
    public boolean UpdateProjectFileStatus(Long fileId, String errmsg, Integer status) {
        CbProjectFile cbProjectFile = new CbProjectFile();
        cbProjectFile.setId(fileId);
        cbProjectFile.setFailRemark(errmsg);
        cbProjectFile.setFileParseStatus(status);
        boolean b = this.updateById(cbProjectFile);
        return b;
    }

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