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

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.base.bsnMessage.appliction.MannualStartWorkApplication;
import com.huigou.topsun.mes.produceException.application.ProduceExceptionApplication;
import com.huigou.topsun.mes.produceException.domain.ProduceException;
import com.huigou.topsun.mes.produceException.domain.query.ProduceExceptionQueryRequest;
import com.huigou.topsun.mes.produceException.domain.vo.ProduceExceptionFeedBack;
import com.huigou.topsun.mes.produceException.domain.vo.ProduceExceptionVo;
import com.huigou.topsun.mes.produceException.repository.ProduceExceptionRepository;
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.bpm.ApprovalParameter;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: xin.lu
 * @Date: 2024/08/12/10:29
 * @Description:
 */
@Service("produceExceptionApplication")
public class ProduceExceptionApplicationImpl extends FlowBroker implements ProduceExceptionApplication {
    @Autowired
    private ProduceExceptionRepository produceExceptionRepository;
    @Autowired
    private WorkflowApplication workflowApplication;
    @Autowired
    private OperatorApplication operatorApplication;
    @Autowired
    private HttpClient httpClient;
    @Autowired
    SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private MannualStartWorkApplication mannualStartWorkApplication;

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

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(produceExceptionRepository.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();
        ProduceException produceException = this.produceExceptionRepository.findOne(bizId);
        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());
            //把本次节点的审批结果记录下来

            //清空，下次赋值
            produceException.setResult(procUnitHandler.getOpinion());
            this.produceExceptionRepository.save(produceException);
        }
    }

    /**
     * 回收事件
     **/
    @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(ProduceException.class, bizId, status.getId());
    }

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

    public void feedBackSaleOrder(ProduceException produceException,String status){
        //日志记录
        Map<String, Object> resultMap = new HashMap<>();
        ProduceExceptionFeedBack produceExceptionFeedBack = new ProduceExceptionFeedBack();
        produceExceptionFeedBack.setExceptionNo(produceException.getExceptionNo());
        produceExceptionFeedBack.setResult(produceException.getResult());
        produceExceptionFeedBack.setStatus(status);
        //produceExceptionFeedBack.setActionType("checkIqcResult");
        try {
            //api/v1/qcAbnormalReport/examineQcAbnormal
            String execute = httpClient.executeForMes(produceExceptionFeedBack, "v1/qcAbnormalReport/examineQcAbnormal");
            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());
            }
            produceException.setCode(mesResult.getCode());
            produceException.setMsg(mesResult.getMsg());
            produceExceptionRepository.save(produceException);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            resultMap.put("businessType", "异常单");
            resultMap.put("businessId", produceException.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();
        ProduceException produceException = produceExceptionRepository.findOne(bizId);
        produceException.setStatusId(BizBillStatus.ABORTED.getId());
        ApprovalParameter approvalParameter = this.getApprovalParameter();
        String handleOpinion = approvalParameter.getHandleOpinion();
        produceException.setResult(handleOpinion);
        produceExceptionRepository.save(produceException);
        this.feedBackSaleOrder(produceException,"N");
    }

    /**
     * @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();
            ProduceException produceException = produceExceptionRepository.findOne(bizId);
            produceException.setStatusId(BizBillStatus.APPLYING.getId());
            TaskExtension te = actApplication.loadRuntimeTaskExtension(delegateTask.getId());
            cn.hutool.core.lang.Assert.notNull(te, String.format("未查询到流程任务【%s】的扩展信息", delegateTask.getId()));
            // 获取流程任务对应的审批环节信息
            ProcUnitHandler procUnitHandler = procUnitHandlerApplication.loadProcUnitHandler(te.getProcUnitHandlerId());
            produceException.setResult(procUnitHandler.getOpinion());
            produceExceptionRepository.save(produceException);
        }
    }

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

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

    @Override
    public ProduceException saveProduceException(ProduceException produceException) {
        return produceExceptionRepository.save(produceException);
    }

    @Override
    public Map<String, Object> slicedProduceExceptionList(ProduceExceptionQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "produceException");
        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 saveMesProduceExceptionVo(ProduceExceptionVo produceExceptionVo) {
        ProduceException produceException = new ProduceException();
        BeanUtil.copyProperties(produceExceptionVo,produceException);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (StringUtil.isNotBlank(produceExceptionVo.getExceptionDate())){
            try {
                Date parse = dateFormat.parse(produceExceptionVo.getExceptionDate());
                produceException.setExceptionDate(parse);
            } catch (ParseException e) {
                throw new RuntimeException("异常日期转换出错："+e.getMessage());
            }
        }
        //初始化用户信息
        String personCode = produceExceptionVo.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);
        ThreadLocalUtil.putOperator(operator);
        produceException.setDefaultValues(new OrgUnit(operator.getFullId(), operator.getFullName()));

        String bizId =mannualStartWorkApplication.startWorkflow(produceException,PROCESS_DEFINITION_KEY,"produceException");
        produceException.setId(bizId);
        produceException.setStatusId(BizBillStatus.APPROVING.getId());
        produceExceptionRepository.save(produceException);
        //this.startProcessInstance(ProduceExceptionApplication.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;
    }
}
