package com.qmth.sop.business.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.sop.business.bean.dto.CrmDetailImportDto;
import com.qmth.sop.business.bean.params.CrmDetailSopParam;
import com.qmth.sop.business.bean.params.SopPublishParam;
import com.qmth.sop.business.bean.result.CrmProjectResult;
import com.qmth.sop.business.bean.result.FlowFormWidgetResult;
import com.qmth.sop.business.entity.*;
import com.qmth.sop.business.mapper.TBCrmDetailMapper;
import com.qmth.sop.business.service.*;
import com.qmth.sop.business.util.excel.BasicExcelListener;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.util.JacksonUtil;
import com.qmth.sop.common.util.ResultUtil;
import com.qmth.sop.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 派单明细表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2024-05-14
 */
@Service
public class TBCrmDetailServiceImpl extends ServiceImpl<TBCrmDetailMapper, TBCrmDetail> implements TBCrmDetailService {

    private final static Logger log = LoggerFactory.getLogger(TBCrmDetailServiceImpl.class);

    @Resource
    TBCrmService tbCrmService;

    @Resource
    TBCrmDetailService tbCrmDetailService;

    @Resource
    TFCustomFlowService tfCustomFlowService;

    @Resource
    TBServiceService tbServiceService;

    @Resource
    TDFormWidgetService tdFormWidgetService;

    @Resource
    TBSopInfoService tbSopInfoService;

    @Resource
    TFCustomFlowEntityService tfCustomFlowEntityService;

    @Resource
    TFFlowApproveService tfFlowApproveService;

    /**
     * 查找派单sop信息
     *
     * @param crmNo
     * @return
     */
    @Override
    public CrmProjectResult sopVarInfo(String crmNo) {
        CrmProjectResult crmProjectResult = tbCrmService.findCrmProjectInfo(null, null, crmNo);
        Objects.requireNonNull(crmProjectResult, "未找到派单信息");

        TBCrm tbCrm = tbCrmService.findByCrmNo(crmNo);
        TBService tbService = tbServiceService.getById(tbCrm.getServiceId());
        Objects.requireNonNull(tbService, "未找到服务单元");

        if (Objects.isNull(crmProjectResult.getProcessVar())) {
            if (tbService.getType() == ProductTypeEnum.OFFICE) {
                List<FlowFormWidgetResult> flowFormWidgetResultList = tdFormWidgetService.flowWidgetQuery(
                        TFCustomTypeEnum.OFFICE_SOP_FLOW, 1, SystemConstant.OFFICE_COMMON_GROUP);
                if (CollectionUtils.isEmpty(flowFormWidgetResultList)) {
                    throw ExceptionResultEnum.ERROR.exception("教务处sop公用控件未设置");
                }
                crmProjectResult.setProcessVar(JacksonUtil.parseJson(flowFormWidgetResultList));
            }
        }
        return crmProjectResult;
    }

    /**
     * 派单明细sop变量保存
     *
     * @param crmDetailSopParam
     * @return
     */
    @Override
    @Transactional
    public boolean sopVarSave(CrmDetailSopParam crmDetailSopParam) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        TBCrm tbCrm = tbCrmService.findByCrmNo(crmDetailSopParam.getCrmNo());
        tbCrm.updateProcessVar(crmDetailSopParam.getProcessVar(), sysUser.getId());
        return tbCrmService.updateById(tbCrm);
    }

    /**
     * 派单明细sop导入
     *
     * @param file
     * @param crmNo
     * @return
     */
    @Override
    @Transactional
    public Map<String, String> sopExcelImport(MultipartFile file, String crmNo) {
        log.debug("导入Excel开始...");
        long start = System.currentTimeMillis();

        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        TFCustomFlow tfCustomFlow = tbCrmDetailService.queryCustomFlow(crmNo);
        Map<String, String> messageMap = new LinkedHashMap<>();
        try {
            StringJoiner errorData = new StringJoiner("");
            StringJoiner successData = new StringJoiner("");

            LinkedMultiValueMap<String, CrmDetailImportDto> crmDetailImportDtoLinkedMultiValueMap = new LinkedMultiValueMap<>();
            EasyExcel.read(file.getInputStream(), CrmDetailImportDto.class,
                    new BasicExcelListener<CrmDetailImportDto>() {

                        @Override
                        public void handle(LinkedMultiValueMap<String, CrmDetailImportDto> dataList,
                                StringJoiner errorDataSj, Exception exception) {
                            crmDetailImportDtoLinkedMultiValueMap.addAll(dataList);
                            errorData.add(errorDataSj.toString());
                        }
                    }).headRowNumber(2).sheet(0).doRead();

            List<CrmDetailImportDto> crmDetailImportDtoList = crmDetailImportDtoLinkedMultiValueMap.get(
                    BasicExcelListener.SUCCESS);
            if (CollectionUtils.isNotEmpty(crmDetailImportDtoList)) {
                if (crmDetailImportDtoList.size() > 1000) {
                    throw ExceptionResultEnum.ERROR.exception("一次最多支持导入1000条");
                }
                List<TBCrmDetail> tbCrmDetailList = new ArrayList<>(crmDetailImportDtoList.size());
                for (int i = 0; i < crmDetailImportDtoList.size(); i++) {
                    CrmDetailImportDto c = crmDetailImportDtoList.get(i);
                    tbCrmDetailList.add(new TBCrmDetail(crmNo, tfCustomFlow.getFlowDeploymentId(), c, sysUser.getId()));
                }
                if (!CollectionUtils.isEmpty(tbCrmDetailList)) {
                    successData.add("共导入").add(crmDetailImportDtoList.size() + "").add("条数据");
                    tbCrmDetailService.saveBatch(tbCrmDetailList);
                }
            }
            messageMap.put(SystemConstant.SUCCESS, successData.length() > 0 ? successData.toString() : "无");
            messageMap.put(SystemConstant.EXCEL_ERROR, errorData.length() > 0 ? errorData.toString() : "无");
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String[] strs = StringUtils.split(errorColumn, "-");
                String[] columns = StringUtils.split(strs[strs.length - 1], "\\'");
                throw ExceptionResultEnum.SQL_ERROR.exception(
                        FieldUniqueEnum.convertToTitle(columns[columns.length - 1]) + ":[" + columns[0] + "]数据不允许重复插入");
            } else if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        log.debug("导入Excel结束...");
        long end = System.currentTimeMillis();
        log.info("============耗时{}秒============:", (end - start) / 1000);
        return messageMap;
    }

    /**
     * 查询派单明细sop信息列表
     *
     * @param iPage
     * @param crmNo
     * @return
     */
    @Override
    public IPage<TBCrmDetail> list(IPage<Map> iPage, String crmNo) {
        return this.baseMapper.list(iPage, crmNo);
    }

    /**
     * 创建/编辑派单明细sop
     *
     * @param tbCrmDetail
     * @return
     */
    @Override
    @Transactional
    public boolean sopSave(TBCrmDetail tbCrmDetail) {
        try {
            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
            if (Objects.isNull(tbCrmDetail.getId())) {//说明创建sop
                TFCustomFlow tfCustomFlow = tbCrmDetailService.queryCustomFlow(tbCrmDetail.getCrmNo());
                tbCrmDetail.createSop(tfCustomFlow.getFlowDeploymentId(), sysUser.getId());
            } else {
                TBCrmDetail tbCrmDetailDb = tbCrmDetailService.getById(tbCrmDetail.getId());
                Objects.requireNonNull(tbCrmDetailDb, "未找到派单sop信息");

                if (tbCrmDetailDb.getStatus() == CrmStatusEnum.PUBLISH) {
                    SopStatusEnum sopStatus = tbSopInfoService.findBySopNo(tbCrmDetailDb.getSopNo());
                    if (sopStatus == SopStatusEnum.START) {
                        throw ExceptionResultEnum.ERROR.exception("该条sop状态已改变，请刷新页面");
                    }
                }
                tbCrmDetail.updateInfo(sysUser.getId());
            }
            return tbCrmDetailService.saveOrUpdate(tbCrmDetail);
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String[] strs = StringUtils.split(errorColumn, "-");
                String[] columns = StringUtils.split(strs[strs.length - 1], "\\'");
                throw ExceptionResultEnum.SQL_ERROR.exception(
                        FieldUniqueEnum.convertToTitle(columns[columns.length - 1]) + ":[" + columns[0] + "]数据不允许重复插入");
            } else if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return false;
    }

    /**
     * 查询自定义流程
     *
     * @param crmNo
     * @return
     */
    @Override
    public TFCustomFlow queryCustomFlow(String crmNo) {
        TBCrm tbCrm = tbCrmService.findByCrmNo(crmNo);
        if (Objects.isNull(tbCrm.getProcessVar()) || Objects.equals(tbCrm.getProcessVar().trim(), "")) {
            throw ExceptionResultEnum.ERROR.exception("请先保存属性【部署方式】【阅卷方式】【扫描场地网络】");
        }
        TBService tbService = tbServiceService.getById(tbCrm.getServiceId());
        Objects.requireNonNull(tbService, "未找到服务单元");

        TFCustomFlow tfCustomFlow = null;
        if (tbService.getType() == ProductTypeEnum.OFFICE) {
            tfCustomFlow = tfCustomFlowService.findMaxVersion(null, null, TFCustomTypeEnum.OFFICE_SOP_FLOW);
        }
        Objects.requireNonNull(tfCustomFlow, "未找到教务处流程");
        return tfCustomFlow;
    }

    /**
     * 派单明细sop发布
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean sopPublish(Long id) throws Exception {
        TBCrmDetail tbCrmDetail = tbCrmDetailService.getById(id);
        Objects.requireNonNull(tbCrmDetail, "未找到派单sop信息");

        if (tbCrmDetail.getStatus() == CrmStatusEnum.PUBLISH) {
            throw ExceptionResultEnum.ERROR.exception("该条派单sop已经发布");
        }
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        tbCrmDetail.updateStatus(CrmStatusEnum.PUBLISH, sysUser.getId());

        TBCrm tbCrm = tbCrmService.findByCrmNo(tbCrmDetail.getCrmNo());
        //发布流程
        TFCustomFlow tfCustomFlow = tbCrmDetailService.queryCustomFlow(tbCrmDetail.getCrmNo());
        if (tfCustomFlow.getType() == TFCustomTypeEnum.CLOUD_MARK_SOP_FLOW) {
            throw ExceptionResultEnum.ERROR.exception("研究生SOP暂不支持发布");
        }
        Map<String, Object> var = new HashMap<>();
        var.put(SystemConstant.CRM_DETAIL, tbCrmDetail);
        var.put(SystemConstant.PROCESS_VAR, tbCrm.getProcessVar());

        SopPublishParam sopPublishParam = new SopPublishParam(tbCrmDetail.getCrmNo(), tbCrmDetail.getId(),
                tfCustomFlow.getFlowDeploymentId(), FlowApprovePassEnum.DRAFT, null, null, var);
        String sopNo = tbSopInfoService.sopPublish(sopPublishParam);
        tbCrmDetail.setSopNo(sopNo);
        return tbCrmDetailService.updateById(tbCrmDetail);
    }

    /**
     * 派单明细sop删除
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean sopDelete(Long id) {
        TBCrmDetail tbCrmDetail = tbCrmDetailService.getById(id);
        Objects.requireNonNull(tbCrmDetail, "未找到派单sop信息");

        if (tbCrmDetail.getStatus() == CrmStatusEnum.PUBLISH) {
            SopStatusEnum sopStatus = tbSopInfoService.findBySopNo(tbCrmDetail.getSopNo());
            if (sopStatus == SopStatusEnum.START) {
                throw ExceptionResultEnum.ERROR.exception("该条sop状态已改变，请刷新页面");
            }
        }
        boolean result = tbCrmDetailService.removeById(tbCrmDetail.getId());
        int count = tbCrmDetailService.count(
                new QueryWrapper<TBCrmDetail>().lambda().eq(TBCrmDetail::getStatus, CrmStatusEnum.PUBLISH));
        if (count == 0) {
            tbCrmService.updateCrmStatus(tbCrmDetail.getCrmNo(), CrmStatusEnum.UN_PUBLISH);
        }
        return result;
    }

    /**
     * 根据sopNo查询派单明细
     *
     * @param sopNo
     * @return
     */
    @Override
    public TBCrmDetail findBySopNo(String sopNo) {
        return tbCrmDetailService.getOne(new QueryWrapper<TBCrmDetail>().lambda().eq(TBCrmDetail::getSopNo, sopNo));
    }

    /**
     * 根据id查询流程状态
     *
     * @param id
     * @return
     */
    @Override
    public FlowStatusEnum findById(Long id) {
        TBCrmDetail tbCrmDetail = tbCrmDetailService.getById(id);
        Objects.requireNonNull(tbCrmDetail, "未找到派单sop信息");

        TFFlowApprove tfFlowApprove = null;
        if (tbCrmDetail.getStatus() == CrmStatusEnum.PUBLISH) {
            TFCustomFlowEntity tfCustomFlowEntity = tfCustomFlowEntityService.getOne(
                    new QueryWrapper<TFCustomFlowEntity>().lambda()
                            .eq(TFCustomFlowEntity::getCode, tbCrmDetail.getSopNo()));
            Optional.ofNullable(tfCustomFlowEntity)
                    .orElseThrow(() -> ExceptionResultEnum.FLOW_ENTITY_NO_DATA.exception());

            tfFlowApprove = tfFlowApproveService.getOne(new QueryWrapper<TFFlowApprove>().lambda()
                    .eq(TFFlowApprove::getFlowId, tfCustomFlowEntity.getFlowId()));
            Optional.ofNullable(tfFlowApprove).orElseThrow(() -> ExceptionResultEnum.FLOW_APPROVE_NO_DATA.exception());
        }
        return Objects.nonNull(tfFlowApprove) ? tfFlowApprove.getStatus() : null;
    }
}
