package com.dsk.cscec.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
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.core.domain.R;
import com.dsk.common.excel.ExcelResult;
import com.dsk.common.exception.ServiceException;
import com.dsk.common.utils.poi.ExcelUtil;
import com.dsk.cscec.constant.CbProjectConstants;
import com.dsk.cscec.domain.*;
import com.dsk.cscec.domain.bo.CbSummaryActualBo;
import com.dsk.cscec.domain.bo.CbSummaryActualListBo;
import com.dsk.cscec.domain.bo.CbSummaryActualLockBo;
import com.dsk.cscec.domain.bo.CbSummaryBo;
import com.dsk.cscec.domain.vo.CbSummaryActualListVo;
import com.dsk.cscec.domain.vo.CbSummaryCostAccountImportVo;
import com.dsk.cscec.domain.vo.CbSummaryProjectImportVo;
import com.dsk.cscec.listener.CbSummaryCostAccountImportListener;
import com.dsk.cscec.listener.CbSummaryProjectImportListener;
import com.dsk.cscec.mapper.*;
import com.dsk.cscec.service.CbSummaryService;
import com.dsk.system.service.ISysOssService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * 成本汇总(CbSummary)表服务实现类
 *
 * @author cyf
 * @since 2024-02-06
 */
@Slf4j
@Service
public class CbSummaryServiceImpl extends ServiceImpl<CbSummaryMapper, CbSummary> implements CbSummaryService {
    @Autowired
    private CbProjectFileMapper cbProjectFileMapper;

    @Autowired
    private CbSummaryActualMapper cbSummaryActualMapper;

    @Autowired
    private CbProjectRecordMapper cbProjectRecordMapper;

    @Autowired
    private CbSummaryActualLockMapper cbSummaryActualLockMapper;

    @Autowired
    private ISysOssService ossService;

    @Override
    public void importCbProject(Long projectId) {
        //获取del_flag为1的文件，若存在则根据fileId删除相关基础数据，并修改文件del_flag为2 todo


        //获取文件信息
        List<CbProjectFile> cbProjectFiles = cbProjectFileMapper.selectList(new LambdaQueryWrapper<CbProjectFile>()
                .eq(CbProjectFile::getProjectId, projectId)
//                .eq(CbProjectFile::getCbStage, cbStage)
                .eq(CbProjectFile::getCbType, CbProjectConstants.CB_TYPE_SUMMARY)
                .eq(CbProjectFile::getFileParseStatus,CbProjectConstants.PROJECT_FILE_STATUS_PREPARING)
        );

        //解析数据
        cbProjectFiles.forEach(cbProjectFile -> {

            if (cbProjectFile.getFileName().contains("项目")) {
                saveCbSummaryProject(projectId,cbProjectFile);
            } else if (cbProjectFile.getFileName().contains("成本科目")) {
                saveCbSummaryCostAccount(projectId,cbProjectFile);
            } else {
                //修改文件状态
                cbProjectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                cbProjectFile.setFailRemark("失败原因：文件名错误");
                cbProjectFileMapper.updateById(cbProjectFile);
            }
        });

    }

    /**
     * 成本汇总-项目汇总导入
     * @param projectId
     * @param file
     * @return
     */
    boolean saveCbSummaryProject(Long projectId, CbProjectFile file){
        //修改文件状态为解析中
        file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSING);
        cbProjectFileMapper.updateById(file);

        //文件下载
        InputStream inputStream = ossService.downFileIO(file.getFileOssId());
        if (ObjectUtil.isNull(inputStream)) {
            file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
            file.setFailRemark("失败原因：文件数据不存在");
            cbProjectFileMapper.updateById(file);
            return false;
        }

        //解析数据
        ExcelResult<CbSummaryProjectImportVo> importVoExcelResult = ExcelUtil.importExcel(inputStream, CbSummaryProjectImportVo.class,new CbSummaryProjectImportListener(projectId,file.getId()));
        log.info(importVoExcelResult.getAnalysis());

        List<CbSummary> addList = BeanUtil.copyToList(importVoExcelResult.getList(), CbSummary.class);
        this.saveBatch(addList);

        //处理父级id
        List<CbSummary> cbSummaryList = baseMapper.selectList(
                new LambdaQueryWrapper<CbSummary>()
                        .eq(CbSummary::getProjectId, projectId)
                        .eq(CbSummary::getCbType, 1)
                        .orderByAsc(CbSummary::getSort)
        );
        for (CbSummary cbSummary:cbSummaryList) {
            if(cbSummary.getLevel()==0){
                continue;
            }
            //获取父级id
            Integer parentLevel = cbSummary.getLevel()-1;
            CbSummary parent = cbSummaryList.stream().filter(summary -> summary.getSort()<cbSummary.getSort()&&summary.getLevel()==parentLevel)
                    .max(Comparator.comparing(CbSummary::getSort)).get();

            cbSummary.setParentId(parent.getId());
        }

        this.updateBatchById(cbSummaryList);
        //修改文件状态为解析成功
        file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
        cbProjectFileMapper.updateById(file);

        return true;
    }


    /**
     * 成本汇总-成本科目汇总导入
     * @param projectId
     * @param file
     * @return
     */
    boolean saveCbSummaryCostAccount(Long projectId,CbProjectFile file) {
        //修改文件状态为解析中
        file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSING);
        cbProjectFileMapper.updateById(file);

        //文件下载
        InputStream inputStream = ossService.downFileIO(file.getFileOssId());
        if (ObjectUtil.isNull(inputStream)) {
            file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
            file.setFailRemark("失败原因：文件数据不存在");
            cbProjectFileMapper.updateById(file);
            return false;
        }

        //解析数据
        ExcelResult<CbSummaryCostAccountImportVo> importVoExcelResult = ExcelUtil.importExcel(inputStream, CbSummaryCostAccountImportVo.class,new CbSummaryCostAccountImportListener(projectId,file.getId()));

        log.info(importVoExcelResult.getAnalysis());

        List<CbSummary> addList = BeanUtil.copyToList(importVoExcelResult.getList(), CbSummary.class);
        this.saveBatch(addList);

        //处理父级id
        List<CbSummary> cbSummaryList = baseMapper.selectList(
                new LambdaQueryWrapper<CbSummary>()
                        .eq(CbSummary::getProjectId, projectId)
                        .eq(CbSummary::getCbType, 1)
                        .orderByAsc(CbSummary::getSort)
        );
        for (CbSummary cbSummary:cbSummaryList) {
            if(cbSummary.getLevel()==0){
                continue;
            }
            //获取父级id
            Integer parentLevel = cbSummary.getLevel()-1;
            CbSummary parent = cbSummaryList.stream().filter(summary -> summary.getSort()<cbSummary.getSort()&&summary.getLevel()==parentLevel)
                    .max(Comparator.comparing(CbSummary::getSort)).get();

            cbSummary.setParentId(parent.getId());
        }

        this.updateBatchById(cbSummaryList);
        //修改文件状态为解析成功
        file.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
        cbProjectFileMapper.updateById(file);

        return true;
    }

    @Override
    public List<Map<String, Object>> getCbNameList(CbSummaryBo bo) {
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
//        Assert.notNull(bo.getCbStage(), "成本阶段不能为空");
        Assert.notNull(bo.getCbType(), "成本类型不能为空");

        List<Map<String, Object>> resultList = new ArrayList<>();

        bo.setLevel(0);
        List<Map<String, Object>> cbNameTop = baseMapper.selectByLevel(bo);

        bo.setLevel(1);
        List<Map<String, Object>> cbNames = baseMapper.selectByLevel(bo);
        resultList.addAll(cbNameTop);
        resultList.addAll(cbNames);

        return resultList;
    }

    @Override
    public List<CbSummaryActualListVo> getActualList(CbSummaryActualListBo bo) {
        Assert.notNull(bo.getId(), "id不能为空");
        Assert.notNull(bo.getCbType(), "成本类型不能为空");
        if (StringUtil.isBlank(bo.getExpenseDate())) {
            //默认当前月
            bo.setExpenseDate(DatePattern.SIMPLE_MONTH_FORMAT.format(new Date()));
        }
        List<CbSummaryActualListVo> list = new ArrayList<>();
        //当前父级数据
        CbSummaryActualListVo cbSummaryActualListVo = baseMapper.getById(bo.getId(), bo.getExpenseDate());
        if (ObjectUtil.isEmpty(cbSummaryActualListVo)) {
            return list;
        }
        //截至本月费用汇总
        Map<String, BigDecimal> parentTotal = cbSummaryActualMapper.getTotal(cbSummaryActualListVo.getId(), bo.getExpenseDate());
        cbSummaryActualListVo.setTaxExclusiveExpenseTotal(parentTotal.get("taxExclusiveExpenseTotal"));
        cbSummaryActualListVo.setTaxInclusiveExpenseTotal(parentTotal.get("taxInclusiveExpenseTotal"));

        List<CbSummaryActualListVo> childrenList = baseMapper.getByParentId(bo.getId(), bo.getExpenseDate());
        //截至本月费用汇总
        childrenList.forEach(children -> {
            Map<String, BigDecimal> total = cbSummaryActualMapper.getTotal(children.getId(), bo.getExpenseDate());
            children.setTaxExclusiveExpenseTotal(total.get("taxExclusiveExpenseTotal"));
            children.setTaxInclusiveExpenseTotal(total.get("taxInclusiveExpenseTotal"));
        });

        if (0 == cbSummaryActualListVo.getLevel() && 1 == bo.getCbType()) {
            //项目汇总一级列表
            return childrenList;
        } else if (0 == cbSummaryActualListVo.getLevel() && 2 == bo.getCbType()) {
            //成本科目汇总一级列表
            cbSummaryActualListVo.setChildren(childrenList);

            list.add(cbSummaryActualListVo);
            return list;
        } else {
            //递归列表
            childrenList = getProjectSumList(bo);
            cbSummaryActualListVo.setChildren(childrenList);

            list.add(cbSummaryActualListVo);
            return list;
        }

    }

    /**
     * 成本汇总递归列表
     *
     * @param bo
     * @return
     */
    private List<CbSummaryActualListVo> getProjectSumList(CbSummaryActualListBo bo) {

        List<CbSummaryActualListVo> childrenList = baseMapper.getByParentId(bo.getId(), bo.getExpenseDate());
        childrenList.forEach(children -> {
            CbSummaryActualListBo childBo = new CbSummaryActualListBo();
            childBo.setId(children.getId());
            childBo.setExpenseDate(bo.getExpenseDate());
            children.setChildren(getProjectSumList(childBo));
            //截至本月费用汇总
            Map<String, BigDecimal> total = cbSummaryActualMapper.getTotal(children.getId(), bo.getExpenseDate());
            children.setTaxExclusiveExpenseTotal(total.get("taxExclusiveExpenseTotal"));
            children.setTaxInclusiveExpenseTotal(total.get("taxInclusiveExpenseTotal"));
        });

        return childrenList;

    }

    @Override
    public List<Map<String, Object>> getExpenseDateList(CbSummaryBo bo) {
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
//        Assert.notNull(bo.getCbStage(),"成本阶段不能为空");
        Assert.notNull(bo.getCbType(), "成本类型不能为空");

        return baseMapper.getExpenseDateList(bo);
    }

    @Override
    public List<String> getLockedList(CbSummaryBo bo) {
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
        Assert.notNull(bo.getCbType(), "成本类型不能为空");

        return cbSummaryActualLockMapper.getLockedList(bo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertOrUpdateActual(List<CbSummaryActualBo> boList) {
        if (CollectionUtil.isEmpty(boList)) {
            return false;
        }
        boList.forEach(bo -> {
            Assert.notNull(bo.getCbSummaryId(), "成本汇总id不能为空");
            Assert.notNull(bo.getExpenseDate(), "费用日期不能为空");

        });

        CbSummary cbSummary = baseMapper.selectById(boList.get(0).getCbSummaryId());
        Assert.isFalse(ObjectUtil.isNull(cbSummary), "成本汇总数据不存在！");

        String expenseDate = boList.get(0).getExpenseDate();
        boolean exists = cbSummaryActualLockMapper.exists(
                new LambdaQueryWrapper<CbSummaryActualLock>()
                        .eq(CbSummaryActualLock::getProjectId, cbSummary.getProjectId())
                        .eq(CbSummaryActualLock::getExpenseDate, expenseDate)
                        .eq(CbSummaryActualLock::getCbType, cbSummary.getCbType())
        );
        Assert.isFalse(exists, "该月成本已锁定");

        List<CbSummaryActual> actualList = BeanUtil.copyToList(boList, CbSummaryActual.class);
        return cbSummaryActualMapper.insertOrUpdateBatch(actualList) > 0;
    }

    @Override
    public R getUnfilled(CbSummaryActualLockBo bo) {
        Assert.notNull(bo.getCbType(), "成本类型不能为空");
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
        Assert.notBlank(bo.getExpenseDate(), "费用日期不能为空");

        StringBuilder unfilled = new StringBuilder();
        //获取一级大类成本id
        List<CbSummary> firstList = baseMapper.selectList(
                new LambdaQueryWrapper<CbSummary>()
                        .eq(CbSummary::getProjectId, bo.getProjectId())
                        .eq(CbSummary::getLevel, 1)
                        .eq(CbSummary::getCbType, bo.getCbType())
                        .orderByAsc(CbSummary::getSort)
        );

        firstList.forEach(firstCb -> {
            //获取大类下的所有子级id
            List<CbSummary> allList = new ArrayList<>();
            allList.add(firstCb);
            allList.addAll(getAllChild(firstCb.getId(), new ArrayList<>()));
            //根据子级id查询是否填写实际成本
            List<CbSummaryActualListVo> vos = baseMapper.getByIds(allList, bo.getExpenseDate());
            if (CollectionUtil.isEmpty(vos)) {
                unfilled.append(firstCb.getCbName()).append("、");
            }
        });

        if (unfilled.length() > 0) {
            unfilled.deleteCharAt(unfilled.lastIndexOf("、"));
            unfilled.append(" 未填写成本，是否继续锁定？");
            return R.fail(unfilled.toString());
        } else {
            return R.ok();
        }
    }

    private List<CbSummary> getAllChild(Long id, List<CbSummary> resultList) {
        List<CbSummary> childList = baseMapper.selectList(
                new LambdaQueryWrapper<CbSummary>()
                        .eq(CbSummary::getParentId, id)
        );
        if (CollectionUtil.isNotEmpty(childList)) {
            resultList.addAll(childList);
            childList.forEach(child -> {
                getAllChild(child.getId(), resultList);
            });
        }

        return resultList;
    }

    @Override
    public boolean lockActual(CbSummaryActualLockBo bo) {
        Assert.notNull(bo.getCbType(), "成本类型不能为空");
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
        Assert.notBlank(bo.getExpenseDate(), "费用日期不能为空");

        boolean exists = cbSummaryActualLockMapper.exists(
                new LambdaQueryWrapper<CbSummaryActualLock>()
                        .eq(CbSummaryActualLock::getProjectId, bo.getProjectId())
                        .eq(CbSummaryActualLock::getExpenseDate, bo.getExpenseDate())
                        .eq(CbSummaryActualLock::getCbType, bo.getCbType())
        );
        Assert.isFalse(exists, "该月成本已锁定，请勿重复操作！");
        CbSummaryActualLock lock = BeanUtil.copyProperties(bo, CbSummaryActualLock.class);
        return cbSummaryActualLockMapper.insert(lock) > 0;
    }

    @Override
    public List<CbSummaryActualListVo> getAll(CbSummaryActualListBo bo) {
        Assert.notNull(bo.getProjectId(), "项目id不能为空");
        Assert.notNull(bo.getCbType(), "成本类型不能为空");
        Assert.notNull(bo.getExpenseDate(), "费用日期不能为空");
        //获取项目成本阶段
        CbProjectRecord cbProjectRecord = cbProjectRecordMapper.selectById(bo.getProjectId());
        if (ObjectUtil.isNull(cbProjectRecord)) {
            throw new ServiceException("当前项目不存在");
        }
//        bo.setCbStage(cbProjectRecord.getCbStage());
        List<CbSummaryActualListVo> resultList = new ArrayList<>();
        if (bo.getCbType() == 1) {
            resultList = baseMapper.getProjectAll(bo);
        } else {
            resultList = baseMapper.getCostAccountAll(bo);
        }
        //截至本月费用汇总
        resultList.forEach(cbSummaryActualListVo -> {
            Map<String, BigDecimal> total = cbSummaryActualMapper.getTotal(cbSummaryActualListVo.getId(), bo.getExpenseDate());
            cbSummaryActualListVo.setTaxExclusiveExpenseTotal(total.get("taxExclusiveExpenseTotal"));
            cbSummaryActualListVo.setTaxInclusiveExpenseTotal(total.get("taxInclusiveExpenseTotal"));
        });
        return resultList;
    }
}
