package com.huigou.topsun.mes.unqualifiedMaterials.application.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huigou.cache.DictUtil;
import com.huigou.context.Operator;
import com.huigou.context.OrgUnit;
import com.huigou.context.ThreadLocalUtil;
import com.huigou.data.domain.model.CommonDomainConstants;
import com.huigou.data.query.model.QueryDescriptor;
import com.huigou.data.query.model.QueryModel;
import com.huigou.topsun.mes.unqualifiedMaterials.application.UnqualifiedMaterialsApplication;
import com.huigou.topsun.mes.unqualifiedMaterials.domain.UnqualifiedMaterials;
import com.huigou.topsun.mes.unqualifiedMaterials.domain.UnqualifiedMaterialsItem;
import com.huigou.topsun.mes.unqualifiedMaterials.domain.query.UnqualifiedMaterialsQueryRequest;
import com.huigou.topsun.mes.unqualifiedMaterials.domain.vo.UnqualifiedMaterialsFeedBack;
import com.huigou.topsun.mes.unqualifiedMaterials.domain.vo.UnqualifiedMaterialsVo;
import com.huigou.topsun.mes.unqualifiedMaterials.repository.UnqualifiedMaterialsItemRepository;
import com.huigou.topsun.mes.unqualifiedMaterials.repository.UnqualifiedMaterialsRepository;
import com.huigou.topsun.sap.common.HttpClient;
import com.huigou.topsun.sap.common.application.SapMutualEpLogApplication;
import com.huigou.topsun.sap.common.domain.MesResult;
import com.huigou.uasp.bmp.common.BizBillStatus;
import com.huigou.uasp.bmp.operator.OperatorApplication;
import com.huigou.uasp.bmp.opm.domain.model.org.Org;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.uasp.bpm.ProcessAction;
import com.huigou.uasp.bpm.ProcessStartModel;
import com.huigou.uasp.bpm.engine.application.WorkflowApplication;
import com.huigou.uasp.bpm.engine.domain.model.ProcUnitHandler;
import com.huigou.uasp.bpm.engine.domain.model.TaskExtension;
import com.huigou.util.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.*;

/**
 * @Auther: xin.lu
 * @Date: 2024/08/12/10:29
 * @Description:
 */
@Service("unqualifiedMaterialsApplication")
public class UnqualifiedMaterialsApplicationImpl extends FlowBroker implements UnqualifiedMaterialsApplication {
    @Autowired
    private UnqualifiedMaterialsRepository unqualifiedMaterialsRepository;
    @Autowired
    private WorkflowApplication workflowApplication;
    @Autowired
    private OperatorApplication operatorApplication;
    @Autowired
    private HttpClient httpClient;
    @Autowired
    SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private UnqualifiedMaterialsItemRepository unqualifiedMaterialsItemRepository;

    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        UnqualifiedMaterials unqualifiedMaterials = getBizEntity(UnqualifiedMaterials.class);
        if (unqualifiedMaterials.isNew()) {
            unqualifiedMaterials.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            unqualifiedMaterials = (UnqualifiedMaterials) commonDomainService.loadAndFillinProperties(unqualifiedMaterials);
        }
        unqualifiedMaterials = unqualifiedMaterialsRepository.save(unqualifiedMaterials);
        return unqualifiedMaterials.getId();
    }

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(unqualifiedMaterialsRepository.getOne(bizId));
    }

    /**
     * 流程撤销事件
     **/
    @Override
    protected void onRecallProcessInstance(DelegateExecution delegateExecution) {
        String bizId = delegateExecution.getProcessBusinessKey();
        // 修改单据状态为申请
        updateStatus(bizId, BizBillStatus.APPLYING);
    }

    /**
     * 任务完成前执行
     */
    @Override
    protected void onBeforeComplete(DelegateTask delegateTask) {
        super.onBeforeComplete(delegateTask);
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        UnqualifiedMaterials unqualifiedMaterials = this.unqualifiedMaterialsRepository.findOne(bizId);
        String result = DictUtil.getDictionaryDetailText("result", unqualifiedMaterials.getResult());
        if (this.isApplyProcUnit(delegateTask) && this.getApprovalParameter().isAdvanceProcessAction()) {
            updateStatus(bizId, BizBillStatus.APPROVING);
        }
        if (this.isApprovalProcUnit(delegateTask) && this.getApprovalParameter().isAdvanceProcessAction()){
            TaskExtension te = actApplication.loadRuntimeTaskExtension(delegateTask.getId());
            cn.hutool.core.lang.Assert.notNull(te, String.format("未查询到流程任务【%s】的扩展信息", delegateTask.getId()));
            // 获取流程任务对应的审批环节信息
            ProcUnitHandler procUnitHandler = procUnitHandlerApplication.loadProcUnitHandler(te.getProcUnitHandlerId());
            String subProcUnitName = procUnitHandler.getSubProcUnitName();
            //把本次节点的审批结果记录下来
            UnqualifiedMaterialsItem materialsItem = unqualifiedMaterialsItemRepository.findByUnqualifiedMaterialsIdAndDept(bizId, subProcUnitName);
            //如果之前审批过，填写了意见，打回或者回退后再次审批时，覆盖之前的意见
            if (Objects.isNull(materialsItem)){
                UnqualifiedMaterialsItem unqualifiedMaterialsItem = new UnqualifiedMaterialsItem();
                unqualifiedMaterialsItem.setUnqualifiedMaterialsId(bizId);
                unqualifiedMaterialsItem.setDept(subProcUnitName);
                unqualifiedMaterialsItem.setResult(result);
                unqualifiedMaterialsItem.setOpinion(procUnitHandler.getOpinion());
                unqualifiedMaterialsItem.setHandlerName(procUnitHandler.getHandlerName());
                unqualifiedMaterialsItemRepository.save(unqualifiedMaterialsItem);
            }else {
                materialsItem.setOpinion(procUnitHandler.getOpinion());
                materialsItem.setResult(result);
                materialsItem.setHandlerName(procUnitHandler.getHandlerName());
                unqualifiedMaterialsItemRepository.save(materialsItem);
            }

            //清空，下次赋值
            //unqualifiedMaterials.setResult(null);
            this.unqualifiedMaterialsRepository.save(unqualifiedMaterials);
        }
    }

    /**
     * 回收事件
     **/
    @Override
    protected void onWithdraw(DelegateTask delegateTask, String destActivityId) {
        super.onWithdraw(delegateTask, destActivityId);
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        if (destActivityId.equalsIgnoreCase("apply")) {
            updateStatus(bizId, BizBillStatus.APPLYING);
        }
    }

    @Transactional
    private void updateStatus(String bizId, BizBillStatus status) {
        Assert.hasText(bizId, CommonDomainConstants.ID_NOT_BLANK);
        this.commonDomainService.updateStatus(UnqualifiedMaterials.class, bizId, status.getId());
    }

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        UnqualifiedMaterials unqualifiedMaterials = unqualifiedMaterialsRepository.findOne(bizId);
        unqualifiedMaterials.setStatusId(status.getId());
        //发送审批结果到MES
        this.feedBackSaleOrder(unqualifiedMaterials);
    }

    public void feedBackSaleOrder(UnqualifiedMaterials unqualifiedMaterials){
        //日志记录
        Map<String, Object> resultMap = new HashMap<>();
        UnqualifiedMaterialsFeedBack unqualifiedMaterialsFeedBack = new UnqualifiedMaterialsFeedBack();
        ClassHelper.copyProperties(unqualifiedMaterials,unqualifiedMaterialsFeedBack);
        unqualifiedMaterialsFeedBack.setActionType("checkIqcResult");
        try {
            String execute = httpClient.executeForMes(unqualifiedMaterialsFeedBack, "v1/iqc/bpmapi");
            MesResult mesResult = JSONObject.parseObject(execute, MesResult.class);
            resultMap.put("TYPE", mesResult.getCode());
            resultMap.put("message", mesResult.getMsg());
            if (!"S".equals(mesResult.getCode())){
                throw new RuntimeException("数据传输失败，"+ mesResult.getMsg());
            }
            unqualifiedMaterials.setCode(mesResult.getCode());
            unqualifiedMaterials.setMsg(mesResult.getMsg());
            unqualifiedMaterialsRepository.save(unqualifiedMaterials);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            resultMap.put("businessType", "IQC");
            resultMap.put("businessId", unqualifiedMaterials.getBillCode());
            resultMap.put("parameter", JSON.toJSONString(resultMap));
            resultMap.put("sequence", resultMap.get("row"));
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }

    @Override
    protected void onAbortProcessInstance(DelegateExecution delegateExecution) {
        super.onAbortProcessInstance(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        UnqualifiedMaterials unqualifiedMaterials = unqualifiedMaterialsRepository.findOne(bizId);
        unqualifiedMaterials.setStatusId(BizBillStatus.ABORTED.getId());
        unqualifiedMaterialsRepository.save(unqualifiedMaterials);
    }

    /**
     * @param delegateTask
     * @param destActivityId 回退到的目标节点id
     */
    @Override
    protected void onBack(DelegateTask delegateTask, String destActivityId) {
        super.onBack(delegateTask, destActivityId);
        if ("Apply".equalsIgnoreCase(destActivityId)) {
            String bizId = delegateTask.getExecution().getProcessBusinessKey();
            UnqualifiedMaterials unqualifiedMaterials = unqualifiedMaterialsRepository.findOne(bizId);
            unqualifiedMaterials.setStatusId(BizBillStatus.APPLYING.getId());
            unqualifiedMaterialsRepository.save(unqualifiedMaterials);

            //回退后，清空评审结果明细
            List<UnqualifiedMaterialsItem> itemList = this.unqualifiedMaterialsItemRepository.findByUnqualifiedMaterialsId(bizId);
            unqualifiedMaterialsItemRepository.delete(itemList);
        }
    }

    /**
     * 设置任务名称
     */
    @Override
    protected void setTaskDescription(DelegateTask delegateTask) {
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        delegateTask.setDescription(this.getApprovalSubjectName(bizId));
    }

    /**
     * 获取任务标题
     *
     * @param bizId
     * @return
     */
    private String getApprovalSubjectName(String bizId) {
        UnqualifiedMaterials unqualifiedMaterials = this.unqualifiedMaterialsRepository.findOne(bizId);
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", unqualifiedMaterials.getFillinDate());
        //设置标题
        return String.format("%s-%s(%s)", "质量异常评审表", unqualifiedMaterials.getBillCode(), fillinDateStr);
    }
    @Override
    public UnqualifiedMaterials findUnqualifiedMaterialsById(String id) {
        return unqualifiedMaterialsRepository.findOne(id);
    }

    @Override
    public UnqualifiedMaterials saveUnqualifiedMaterials(UnqualifiedMaterials unqualifiedMaterials) {
        return unqualifiedMaterialsRepository.save(unqualifiedMaterials);
    }

    @Override
    public Map<String, Object> slicedUnqualifiedMaterialsList(UnqualifiedMaterialsQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "unqualifiedMaterials");
        QueryModel queryModel = this.sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest);
        queryModel.putDictionary("status", BizBillStatus.getMap());
        Map<String, Object> map = this.sqlExecutorDao.executeSlicedQuery(queryModel);
        return map;
    }

    @Override
    public void saveMesUnqualifiedMaterialsVo(UnqualifiedMaterialsVo unqualifiedMaterialsVo) {
        UnqualifiedMaterials unqualifiedMaterials = new UnqualifiedMaterials();
        BeanUtil.copyProperties(unqualifiedMaterialsVo,unqualifiedMaterials);

        //初始化用户信息
        String personCode = unqualifiedMaterialsVo.getSubmitter();
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery("config/topsun/ep/epSaleOrder/epSaleOrder.xml", "loadPersonMemberId");
        String personMemberId = this.sqlExecutorDao.queryToString(queryDescriptor.getSql(), personCode);
        if (StringUtil.isBlank(personMemberId)){
            throw new RuntimeException("未找到编码为：" + personCode + " 的人员");
        }
        Operator operator = operatorApplication.createOperatorByPersonMemberId(personMemberId);
        SDO localSdo = new SDO();
        localSdo.setOperator(operator);
        unqualifiedMaterials.setDefaultValues(new OrgUnit(operator.getFullId(), operator.getFullName()));

        Map<String, Object> formData = BeanUtil.beanToMap(unqualifiedMaterials);
        this.startProcessInstance(UnqualifiedMaterialsApplication.PROCESS_DEFINITION_KEY, formData, localSdo);
    }

    public String startProcessInstance(String processDefinitionKey,Map<String, Object> formData, SDO localSdo){
        Map<String, Object> variables = new HashMap();
        // 将业务数据传递给工作流
        formData.forEach(localSdo::putProperty);
        // 将业务流程信息传递给工作流
        localSdo.putProperty("processAction", ProcessAction.SAVE);
        localSdo.putProperty("procUnitId", "Apply");
        ThreadLocalUtil.putVariable(Constants.SDO, localSdo);
        variables.put("startModel", ProcessStartModel.MANUAL.getId());
        Operator operator = localSdo.getOperator();
        variables.put("executorFullId", operator.getFullId());
        variables.put("executorFullName", operator.getFullName());
        ThreadLocalUtil.putOperator(operator);
        ThreadLocalUtil.putVariable("client.ip", "127.0.0.1");
        ProcessInstance processInstance = this.workflowApplication.startProcessInstanceByKey(processDefinitionKey, variables);
        String businessKey = processInstance.getBusinessKey();
        return businessKey;
    }
}
