package com.dsk.cscec.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
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.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.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.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@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<CbCostMeasureActualVo> selectDataList(CbCostMeasureActualBo costMeasureActualBo) {
        List<CbCostMeasureActualVo> dataList = new ArrayList<>();

        Assert.notNull(costMeasureActualBo.getProjectId(), "项目ID不能为空");
        CbProjectRecord byId = cbProjectRecordService.getById(costMeasureActualBo.getProjectId());
        Assert.notNull(byId, "项目信息不能为空");
        //查询项目某项措施费所有计划成本
        dataList = baseMapper.selectListByProjectAndNo(costMeasureActualBo);
//        if (CollectionUtil.isEmpty(dataList)) {
//            return dataList;
//        }
//        // 查询项目某项措施费某月所有实际成本
//       List<CbCostMeasureActualVo> actualVoList= cbCostMeasureActualMapper.selectDataList(costMeasureActualBo);
//        if (CollectionUtil.isEmpty(actualVoList)) {
//            return dataList;
//        }
//        for (CbCostMeasureActualVo cbCostMeasureActualVo : actualVoList) {
//
//        }

        return dataList;
    }

    @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;
    }


    /**
     * 根据当前序号、项目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;
    }


}
