package com.dsk.cscec.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dsk.common.excel.ExcelResult;
import com.dsk.common.helper.LoginHelper;
import com.dsk.common.utils.JsonUtils;
import com.dsk.common.utils.TreeBuildUtils;
import com.dsk.common.utils.poi.ExcelUtil;
import com.dsk.cscec.constant.CbProjectConstants;
import com.dsk.cscec.domain.*;
import com.dsk.cscec.domain.bo.CbCostMeasureActualBo;
import com.dsk.cscec.domain.bo.CbCostMeasureActualPushBo;
import com.dsk.cscec.domain.bo.CbCostMeasureActualSaveBo;
import com.dsk.cscec.domain.vo.CbCostMeasureActualVo;
import com.dsk.cscec.domain.vo.CbCostMeasuresImportVo;
import com.dsk.cscec.domain.vo.CbProjectExpenseSummaryImportVo;
import com.dsk.cscec.domain.vo.CbProjectExpenseSummaryVo;
import com.dsk.cscec.listener.ProjectCostMeasureImportListener;
import com.dsk.cscec.listener.ProjectCostMeasureSummaryImportListener;
import com.dsk.cscec.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dsk.cscec.mapper.CbCostMeasureMapper;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CbCostMeasureServiceImpl extends ServiceImpl<CbCostMeasureMapper, CbCostMeasure> implements ICbCostMeasureService {


    private final String firstPattern = "[\\(（]*[一|二|三|四|五|六|七|八|九|十]+[\\)）]*";
    private final Pattern secondPattern = Pattern.compile("^\\d+(\\.\\d+)*$");
    private final Pattern pattern3 = Pattern.compile("^([1-9][0-9]*|0)$");

    @Autowired
    private CbProjectRecordService cbProjectRecordService;


    @Autowired
    private ICbCostMeasureActualService cbCostMeasureActualService;

    @Autowired
    private CbProjectFileService cbProjectFileService;


    @Autowired
    private CbProjectExpenseSummaryService cbProjectExpenseSummaryService;

    @SneakyThrows
    @Override
    public void importExcelData(InputStream inputStream, String fileName, Long fileId, Long projectId) {
        // 检查项目
        checkProjectExist(projectId);
        ProjectCostMeasureImportListener importListener = new ProjectCostMeasureImportListener(projectId);
        EasyExcel.read(inputStream, CbCostMeasuresImportVo.class, importListener).sheet().doRead();
        ExcelResult<CbCostMeasuresImportVo> result = importListener.getExcelResult();
        String analysis = result.getAnalysis();
        List<CbCostMeasuresImportVo> list = result.getList();
        List<String> errorList = result.getErrorList();
        if (CollectionUtil.isNotEmpty(errorList) || CollectionUtil.isEmpty(list)) {
            //解析失败
            log.debug(">>>>解析失败" + list.size());
            //todo 解析失败更新文件备注
            cbProjectFileService.UpdateProjectFileStatus(fileId, analysis, CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
            return;
        }
        log.debug(">>>>" + list.size());

        //删除 该项目历史解析数据
        LambdaQueryWrapper<CbCostMeasure> summaryLambdaQueryWrapper = Wrappers.lambdaQuery();
        summaryLambdaQueryWrapper.eq(CbCostMeasure::getProjectId, projectId);
        summaryLambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(fileId), CbCostMeasure::getProjectFileId, fileId);
        this.remove(summaryLambdaQueryWrapper);

        CbCostMeasure rootCbCostMeasure = new CbCostMeasure();
        rootCbCostMeasure.setItemContent(fileName);
        rootCbCostMeasure.setLevel(0);
        rootCbCostMeasure.setParentId(0L);
        rootCbCostMeasure.setProjectId(projectId);
        if (ObjectUtil.isNotEmpty(fileId)) {
            rootCbCostMeasure.setProjectFileId(fileId);
        }


        LambdaQueryWrapper<CbCostMeasure> tWrapper = Wrappers.lambdaQuery(rootCbCostMeasure);
        CbCostMeasure rootMeasure = this.getOne(tWrapper);
        if (ObjectUtil.isEmpty(rootMeasure)) {
            this.save(rootCbCostMeasure);
            rootCbCostMeasure.setNo(String.valueOf(rootCbCostMeasure.getId()));
            this.updateById(rootCbCostMeasure);
        }

        Long rootMeasuresId = rootCbCostMeasure.getId();
        if (CollectionUtil.isNotEmpty(list)) {
            for (CbCostMeasuresImportVo importVo : list) {
                String number = importVo.getNumber();

                CbCostMeasure cbCostMeasure = new CbCostMeasure();
                cbCostMeasure.setProjectId(projectId);
                cbCostMeasure.setProjectFileId(fileId);
                //保存一级节点
                if (ReUtil.isMatch(firstPattern, number) || ReUtil.isMatch(pattern3, number)) {
                    BeanUtil.copyProperties(importVo, cbCostMeasure);
                    cbCostMeasure.setParentId(rootMeasuresId);
                    cbCostMeasure.setLevel(1);

                } else if (ReUtil.isMatch(secondPattern, number)) {
                    BeanUtil.copyProperties(importVo, cbCostMeasure);
                    // 根据no查询父级节点
                    CbCostMeasure parentCbCostMeasure = getCbCostMeasure(rootMeasuresId, number, projectId);
                    String[] split = number.split("\\.");
                    cbCostMeasure.setLevel(split.length);
                    cbCostMeasure.setParentId(parentCbCostMeasure.getId());
                }
                String newNo = String.valueOf(rootMeasuresId).concat(".").concat(cbCostMeasure.getNo());
                cbCostMeasure.setNo(newNo);
                this.save(cbCostMeasure);
            }

            cbProjectFileService.UpdateProjectFileStatus(fileId, null, CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
        }

    }

    @Override
    public List<Map<String, Object>> listByLevel(Long projectId, int i) {

        CbProjectRecord byId = cbProjectRecordService.getById(projectId);
        Assert.notNull(byId, "项目信息不能为空");

        CbCostMeasure rootCbCostMeasure = new CbCostMeasure();
        rootCbCostMeasure.setParentId(0L);
        rootCbCostMeasure.setProjectId(projectId);

        QueryWrapper<CbCostMeasure> tWrapper = Wrappers.query(rootCbCostMeasure);
        tWrapper.select("id", "item_content as itemContent");
        tWrapper.orderByAsc("id");
        List<Map<String, Object>> mapList = this.listMaps(tWrapper);

        return mapList;
    }

    @Override
    public List<Tree<Long>> selectDataList(CbCostMeasureActualBo costMeasureActualBo) {
        List<CbCostMeasureActualVo> dataList = new ArrayList<>();

        Assert.notNull(costMeasureActualBo.getProjectId(), "项目ID不能为空");
        checkProjectExist(costMeasureActualBo.getProjectId());
        //查询项目某项措施费所有计划成本
        dataList = baseMapper.selectListByProjectAndNo(costMeasureActualBo);

//配置类
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("parentId");
        treeNodeConfig.setChildrenKey("childrens");
//构建树形
        List<Tree<Long>> trees = TreeUtil.build(dataList, costMeasureActualBo.getId(), treeNodeConfig, ((object, treeNode) -> {
            treeNode.setId(object.getId());//id
            treeNode.setParentId(object.getParentId());//父id
            // 扩展属性 ...
            treeNode.putExtra("itemContent", object.getItemContent());
            treeNode.putExtra("number", object.getNumber());
            treeNode.putExtra("workContent", object.getWorkContent());
            treeNode.putExtra("unit", object.getUnit());
            treeNode.putExtra("quantity", object.getQuantity());
            treeNode.putExtra("unitPriceExcludingTax", object.getUnitPriceExcludingTax());
            treeNode.putExtra("usageTime", object.getUsageTime());
            treeNode.putExtra("amountExcludingTax", object.getAmountExcludingTax());
            treeNode.putExtra("taxRate", object.getTaxRate());
            treeNode.putExtra("amountIncludingTax", object.getAmountIncludingTax());
            treeNode.putExtra("amortizationRatio", object.getAmortizationRatio());
            treeNode.putExtra("amountIncludeTaxAmortized", object.getAmountIncludeTaxAmortized());
            treeNode.putExtra("amountExcludeTaxAmortized", object.getAmountExcludeTaxAmortized());
            treeNode.putExtra("taxAmount", object.getTaxAmount());
            treeNode.putExtra("remarks", object.getRemarks());
            treeNode.putExtra("costSubject", object.getCostSubject());
            treeNode.putExtra("taxType", object.getTaxType());
            treeNode.putExtra("planMeasureId", object.getPlanMeasureId());
            treeNode.putExtra("monthCostRate", object.getMonthCostRate());
            treeNode.putExtra("costEffective", object.getCostEffective());
            treeNode.putExtra("currentProjectVolume", object.getCurrentProjectVolume());
            treeNode.putExtra("submitProjectVolume", object.getSubmitProjectVolume());
            treeNode.putExtra("month", object.getMonth());
            treeNode.putExtra("pushTime", object.getPushTime());
            treeNode.putExtra("pushDataJson", object.getPushDataJson());
            treeNode.putExtra("createTime", object.getCreateTime());
        }));

        return trees;
    }

    @Override
    public void saveBatchCostMeasureActual(List<CbCostMeasureActualSaveBo> boList) {
        List<CbCostMeasureActual> saveList = new ArrayList<>();
        for (CbCostMeasureActualSaveBo cbCostMeasureActualSaveBo : boList) {
            CbCostMeasureActual cbCostMeasureActual = new CbCostMeasureActual();
            BeanUtil.copyProperties(cbCostMeasureActualSaveBo, cbCostMeasureActual);
            cbCostMeasureActual.setDelFlag(0);
            cbCostMeasureActual.setUpdateId(LoginHelper.getUserId());
            cbCostMeasureActual.setUpdateUser(LoginHelper.getUsername());
            saveList.add(cbCostMeasureActual);
        }
        cbCostMeasureActualService.saveOrUpdateBatch(saveList);
    }

    @Override
    public void pushCostMeasureActual(CbCostMeasureActualPushBo pushBo) {

        //todo 推送到Ipm系统

        CbCostMeasureActual cbCostMeasureActual = new CbCostMeasureActual();
        cbCostMeasureActual.setId(pushBo.getId());
        cbCostMeasureActual.setPushTime(new Date());
        cbCostMeasureActual.setPushDataJson(JsonUtils.toJsonString(pushBo));
        cbCostMeasureActualService.updateById(cbCostMeasureActual);
    }

    @SneakyThrows
    @Override
    public List<String> importExcelSummaryData(InputStream inputStream, Long projectId, Long fileId, Integer dataType) {
        CbProjectRecord byId = cbProjectRecordService.getById(projectId);
        Assert.notNull(byId, "项目信息不能为空");

        // 删除历史数据
        LambdaUpdateWrapper<CbProjectExpenseSummary> summaryLambdaQueryWrapper = Wrappers.lambdaUpdate();
        summaryLambdaQueryWrapper.eq(CbProjectExpenseSummary::getProjectId, projectId);
        summaryLambdaQueryWrapper.eq(CbProjectExpenseSummary::getDataType, 2);
        cbProjectExpenseSummaryService.remove(summaryLambdaQueryWrapper);

        ExcelResult<CbProjectExpenseSummaryImportVo> excelResult = ExcelUtil.importExcel(inputStream, CbProjectExpenseSummaryImportVo.class, new ProjectCostMeasureSummaryImportListener(projectId, fileId, dataType));
        List<String> errorList = excelResult.getErrorList();
        if (CollectionUtil.isNotEmpty(errorList) || CollectionUtil.isEmpty(excelResult.getList())) {
            return errorList;
        }
        return null;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void parseCbCostMeasureFile(Long projectId) {
        // 检查项目
        checkProjectExist(projectId);

        //获取项目待解析文件
        List<CbProjectFile> cbProjectFiles = new ArrayList<>();
        cbProjectFiles = cbProjectFileService.list(new LambdaQueryWrapper<CbProjectFile>()
                .eq(CbProjectFile::getProjectId, projectId)
                .eq(CbProjectFile::getFileParseStatus, CbProjectConstants.PROJECT_FILE_STATUS_PARSING)
                .eq(CbProjectFile::getCbType, CbProjectConstants.CB_TYPE_MEASURE_PROJECT)
        );
        if (CollectionUtil.isEmpty(cbProjectFiles)) {
            log.debug("措施费数据文件不存在");
            return;
        }

        for (CbProjectFile cbProjectFile : cbProjectFiles) {
            String fileName = cbProjectFile.getFileName();
            String prefix = FileNameUtil.getPrefix(fileName);
            // 解析汇总
            if ("措施费".equals(prefix)) {
                byte[] bytes = HttpUtil.downloadBytes(cbProjectFile.getFileOssUrl());
                InputStream inputStream = new ByteArrayInputStream(bytes);
                List<String> errlist = importExcelSummaryData(inputStream, projectId, cbProjectFile.getId(), 2);
                if (CollectionUtil.isNotEmpty(errlist)) {
                    cbProjectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                } else {
                    // 修改文件解析状态
                    cbProjectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
                }
                cbProjectFileService.updateById(cbProjectFile);
            } else {
                byte[] bytes = HttpUtil.downloadBytes(cbProjectFile.getFileOssUrl());
                InputStream inputStream = new ByteArrayInputStream(bytes);
                importExcelData(inputStream, prefix, cbProjectFile.getId(), projectId);
            }


        }

    }

    private void checkProjectExist(Long projectId) {
        CbProjectRecord byId = cbProjectRecordService.getById(projectId);
        Assert.notNull(byId, "项目信息不能为空");
    }


    @Override
    public boolean reparseCbCostMeasureFile(Long projectId, Long projectFileId) {
        // 查询项目
        CbProjectRecord byId = cbProjectRecordService.getById(projectId);
        Assert.notNull(byId, "项目信息不能为空");
        List<CbProjectFile> cbProjectFiles = new ArrayList<>();
        Assert.notNull(projectFileId, "措施费文件ID不能为空");
        if (ObjectUtil.isNotEmpty(projectFileId)) {
            CbProjectFile cbProjectFile = cbProjectFileService.getById(projectFileId);
            Assert.notNull(cbProjectFile, "措施费导入文件不存在");
            String fileName = cbProjectFile.getFileName();
            String prefix = FileNameUtil.getPrefix(fileName);
            // 解析汇总
            if ("措施费".equals(prefix)) {
                byte[] bytes = HttpUtil.downloadBytes(cbProjectFile.getFileOssUrl());
                InputStream inputStream = new ByteArrayInputStream(bytes);
                List<String> errlist = importExcelSummaryData(inputStream, projectId, projectFileId, 2);
                if (CollectionUtil.isNotEmpty(errlist)) {
                    cbProjectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_FAIL);
                } else {
                    // 修改文件解析状态
                    cbProjectFile.setFileParseStatus(CbProjectConstants.PROJECT_FILE_STATUS_PARSE_SUCCESS);
                }

            } else {
                byte[] bytes = HttpUtil.downloadBytes(cbProjectFile.getFileOssUrl());
                InputStream inputStream = new ByteArrayInputStream(bytes);
                importExcelData(inputStream, prefix, cbProjectFile.getId(), projectId);
            }

            //更新

            return true;
        }


        return false;
    }

    @Override
    public String lastProjectVolume(Long measuresId) {
        LambdaQueryWrapper<CbCostMeasureActual> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(CbCostMeasureActual::getPlanMeasureId, measuresId)
                          .isNotNull(CbCostMeasureActual::getPushTime)
                          .orderByDesc(CbCostMeasureActual::getUpdateTime).last(" limit 1");
        CbCostMeasureActual cbCostMeasureActual = cbCostMeasureActualService.getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNotEmpty(cbCostMeasureActual)) {
            return cbCostMeasureActual.getPushDataJson();
        }
        return null;
    }

    @Override
    public List<String> actualMonthList(CbCostMeasureActualBo cbCostMeasureBo) {
        List<String> months = baseMapper.actualMonthList(cbCostMeasureBo);
        return months;
    }

    @Override
    public List<CbProjectExpenseSummaryVo> getSummaryData(Long projectId, Integer dataType, String month) {
        List<CbProjectExpenseSummaryVo> dataList = new ArrayList<>();

        List<CbProjectExpenseSummary> cbProjectExpenseSummaries = cbProjectExpenseSummaryService.queryCbSceneExpenseSummaryDataByType(projectId, dataType);
        if (CollectionUtil.isEmpty(cbProjectExpenseSummaries)) {
            return new ArrayList<>();
        }
        Map<String, BigDecimal> map = new HashMap<>();
        //查询本月实际工程量
        List<CbCostMeasureActualVo> monthActualCostList = cbCostMeasureActualService.getMonthActualCostList(projectId, month);
        if (CollectionUtil.isNotEmpty(monthActualCostList)) {
            map = monthActualCostList.stream()
                                     .collect(Collectors.toMap(
                                             CbCostMeasureActualVo::getItemContent,     // 把CbCostMeasureActualVo属性提取为map的key
                                             CbCostMeasureActualVo::getCostEffective    // 把CbCostMeasureActualVo属性提取为map的value
                                     ));
        }

        for (CbProjectExpenseSummary cbProjectExpenseSummary : cbProjectExpenseSummaries) {
            CbProjectExpenseSummaryVo summaryVo = BeanUtil.copyProperties(cbProjectExpenseSummary, CbProjectExpenseSummaryVo.class);
            summaryVo.setMonthsProjectQuantity(map.get(cbProjectExpenseSummary.getExpenseName()));
            dataList.add(summaryVo);

        }


        return dataList;
    }


    /**
     * 根据当前序号、项目id、成本阶段查询父级信息
     *
     * @param number
     * @param projectId
     * @param cbStage
     * @return
     */
    public CbCostMeasure getCbCostMeasure(Long rootMeasuresId, String number, Long projectId) {
        String parentNo = number.substring(0, number.lastIndexOf('.'));
        parentNo = String.valueOf(rootMeasuresId).concat(".").concat(parentNo);
        CbCostMeasure rootCbCostMeasure = new CbCostMeasure();
        rootCbCostMeasure.setNo(parentNo);
        rootCbCostMeasure.setProjectId(projectId);
        LambdaQueryWrapper<CbCostMeasure> tWrapper = Wrappers.lambdaQuery(rootCbCostMeasure);
        CbCostMeasure rootMeasure = this.getOne(tWrapper);
        return rootMeasure;
    }


}
