package com.junmp.jyzb.listener;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.junmp.junmpProcess.dto.UserListDTO;
import com.junmp.junmpProcess.dto.json.ChildNode;
import com.junmp.junmpProcess.dto.json.UserInfo;
import com.junmp.junmpProcess.mapper.OrgUserMapper;
import com.junmp.junmpProcess.utils.RabbitMQUtils2;
//import com.rabbitmq.client.Channel;
//import com.rabbitmq.client.Connection;
import com.junmp.jyzb.api.bean.dto.MQDto;
import com.junmp.jyzb.api.bean.dto.OrderDto;
import com.junmp.jyzb.api.bean.query.BussinessOrderDetialReq;
import com.junmp.jyzb.api.bean.query.InAndOutRecordReq.DetailJsonReq;
import com.junmp.jyzb.api.bean.query.OrderMainReq;
import com.junmp.jyzb.api.bean.req.UpdateBusFormReq;
import com.junmp.jyzb.api.bean.req.UpdateOrderDetailReq;
import com.junmp.jyzb.api.bean.req.UpdateOrderReq;
import com.junmp.jyzb.api.bean.req.UpdateReassignmentReq;
import com.junmp.jyzb.api.exception.enums.InventoryExceptionEnum;
import com.junmp.jyzb.api.exception.enums.OrderExceptionEnum;
import com.junmp.jyzb.entity.*;
import com.junmp.jyzb.service.*;
import com.junmp.jyzb.utils.DateTimeUtil;
import com.junmp.jyzb.utils.RabbitMQSendMsg;
import com.junmp.v2.common.exception.base.ServiceException;
import com.junmp.v2.common.util.BeanPlusUtil;
import com.junmp.v2.message.api.MessageApi;
import com.junmp.v2.message.api.bean.req.MessageReq;
import com.junmp.v2.message.api.bean.req.MessageSendReq;
import com.junmp.v2.sys.user.entity.SysUserOrg;
import com.junmp.v2.sys.user.service.SysUserOrgService;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import liquibase.pro.packaged.S;
import lombok.SneakyThrows;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.beans.Transient;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.junmp.junmpProcess.common.CommonConstants.*;


@Component
    public class GlobalEndListener extends AbstractFlowableEngineEventListener {
    @Resource
    public OrderMainService orderMainService;

    @Resource
    public OrderDetailService orderDetailService;
    @Resource
    private HistoryService historyService;

    @Resource
    private BusFormService busFormService;

    @Resource
    private PolicemanService policemanService;
    @Resource
    private ReassignmentService reassignmentService;

    @Resource
    private StocktakeService stocktakeService;

    @Resource
    private InventorySummaryService inventorySummaryService;

    @Resource
    private LogSummaryService logSummaryService;
    @Resource
    private LogDetailService logDetailService;

    @Resource
    private MessageApi messageApi;
    @Resource
    private BussinessInventoryService bussinessInventoryService;
    @Autowired
    private RabbitMQSendMsg MQ;

    @Resource
    private OrgUserMapper orgUserMapper;

    @Resource
    private SysUserOrgService sysUserOrgService;
    @Resource
    private RepositoryService repositoryService;
        protected Logger logger = LoggerFactory.getLogger(this.getClass());

        @Transactional(rollbackFor = Exception.class)
        @SneakyThrows
        @Override
        public void processCompleted(FlowableEngineEntityEvent event) {


            if (event.getType() == FlowableEngineEventType.PROCESS_COMPLETED) {
                // 获取流程实例ID
                String processInstanceId = event.getProcessInstanceId();

                Process mainProcess = repositoryService.getBpmnModel(event.getProcessDefinitionId()).getMainProcess();
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .includeProcessVariables()
                        .singleResult();
                // 获取流程定义ID
                String processDefinitionId = event.getProcessDefinitionId();
                List<HistoricVariableInstance> typeOrder = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName("typeOrder").list();

                if(typeOrder.size()>0) {


                    String Type= typeOrder.get(0).getValue().toString();
                    if (Type.equals("workOrder") || Type.equals("quickOrder"))//出入库单据
                    {
                        OrderMain existOrder= orderMainService.getOne(new LambdaQueryWrapper<OrderMain>()
                                .eq(OrderMain::getProcessId, processInstanceId));
                        existOrder.setExamineState("finished");
                        existOrder.setOrderState("ready");
                        UpdateOrderReq updateOrderReq = new UpdateOrderReq();
                        BeanPlusUtil.copyProperties(existOrder,updateOrderReq);
                        List<OrderDetail> list = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>()
                                .eq(OrderDetail::getOrderId, updateOrderReq.getId()));
                        updateOrderReq.setId(existOrder.getId());
                        existOrder.setActualQuantity(0);
                        orderMainService.updateById(existOrder);
//                        orderMainService.ChangeOrderState(updateOrderReq);
                        List<UpdateOrderDetailReq> collect = list.stream().map(orderDetail -> {
                            UpdateOrderDetailReq updateOrderDetailReq = new UpdateOrderDetailReq();
                            BeanPlusUtil.copyProperties(orderDetail, updateOrderDetailReq);
                            if (ObjectUtil.isNotNull(orderDetail.getProductionDate())){
                                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                                updateOrderDetailReq.setProductionDate(format.format(orderDetail.getProductionDate()));
                            }
                            orderDetail.setActualNum(0);
                            orderDetail.setModifyQuantity(0);
                            return updateOrderDetailReq;
                        }).collect(Collectors.toList());
                        orderDetailService.updateBatchById(list);
                        updateOrderReq.setDetailList(collect);
                        //将单据上传到rabbitmq
                        orderMainService.AddFinishOrder(updateOrderReq);
                    } else
                    //业务单据
                    if (Type.equals("bussinessOrder")){
                        BusForm busForm = busFormService.getOne(new LambdaQueryWrapper<BusForm>()
                                .eq(BusForm::getProcessId, processInstanceId));
                        busForm.setExamineState("finished");
                        if (busForm.getBussinessType().equals("remove")){
                            busFormService.updateBrokenResult(busForm);
                        }
                        //如果业务单是调拨单，那么该单子需要让双方都能发物单位和收物单位的仓管员和审核员都能看见
                        // （前提是发起单据的那一方只有发起人或者经办人和审批人员可见，同级人员不可见）
                        //获取申请人判断是调拨单的哪一方发起的
                        String agentId = busForm.getAgentId();
                        Long angentOrgId = sysUserOrgService.getOne(new LambdaQueryWrapper<SysUserOrg>()
                                .eq(SysUserOrg::getUserId, agentId)).getOrgId();
                        Long orgId=(busForm.getStartOrgId() == angentOrgId?busForm.getEndOrgId():busForm.getStartOrgId());
                        //将单子信息指定给另一方的仓管员和审核员可见
                        //获取组织机构下的所有仓管员和审核员id
                        String roleList="(1663372320355389441,1528003832557232130)";

                        List<UserListDTO> userList=orgUserMapper.QueryUserByRoleIdAndOrg(roleList,orgId.toString());
                        List<String> assigneeList=new ArrayList<>();
                        if (userList.size()>0)//判断有没有启动的当前单据,并且下一审核人信息不为空,有启动的单据则把审核人信息加入
                        {
                            for (UserListDTO userId :userList)
                            {
                                assigneeList.add(userId.getUserID());
                            }
                            String assigneeString = String.join(",", assigneeList);
                            if (ObjectUtil.isNull(busForm.getHistoryAssign())){
                                busForm.setHistoryAssign(assigneeString);
                            }else {
                                busForm.setHistoryAssign(busForm.getHistoryAssign()+","+assigneeString);
                            }
                        }
                        busFormService.updateById(busForm);
                    } else
                    if (Type.equals("reassignment")){//调岗申请单
                        Reassignment one = reassignmentService.getOne(new LambdaQueryWrapper<Reassignment>()
                                .eq(Reassignment::getProcessId, processInstanceId));
                        UpdateReassignmentReq updateReassignmentReq = new UpdateReassignmentReq();
                        one.setExamineState("finished");
                        BeanPlusUtil.copyProperties(one,updateReassignmentReq);
                        //如果同意直接讲警员基础信息进行修改
                        policemanService.changePoliceOrg(updateReassignmentReq);
                        reassignmentService.updateById(one);
                    } else
                    if (Type.equals("stocktakeOrder")){//盘库申请单

                        String exchangeName="orderExchange";
                        //需要判断是入库单还是出库单，入库单传收物单位id，出库单传发物单位id
                        BussinessInventory BI = bussinessInventoryService.getOne(new LambdaQueryWrapper<BussinessInventory>()
                                .eq(BussinessInventory::getProcessId, processInstanceId));
                        BI.setExamineState("finished");
                        BI.setApi("BussinessInventory");
                        bussinessInventoryService.updateById(BI);
                        MQ.SendMsg(exchangeName,BI.getOrgId().toString(),BI);

                    } else
                    if (Type.equals("normalOrder")){
                        OrderMain existOrder= orderMainService.getOne(new LambdaQueryWrapper<OrderMain>()
                                .eq(OrderMain::getProcessId, processInstanceId));
                        existOrder.setExamineState("finished");
                        existOrder.setOrderState("finished");
                        List<OrderDetail> list = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>()
                                .eq(OrderDetail::getOrderId, existOrder.getId()));

                        //通过summaryId将出库记录取出来，并且分类存入orderDetail中
                        LogSummary one = logSummaryService.getOne(new LambdaQueryWrapper<LogSummary>()
                                .eq(LogSummary::getOrderMainId, existOrder.getId()));

                        List<LogDetail> logDetailList = logDetailService.list(new LambdaQueryWrapper<LogDetail>()
                                .eq(LogDetail::getSummaryId, one.getId()));
                        Map<String, DetailJsonReq> map=new HashMap<>();
                        for (LogDetail logDetail:logDetailList){
                            String key=logDetail.getTypeId()+logDetail.getSizeId()+logDetail.getPrice()+logDetail.getProperty();
                            if (map.containsKey(key)){
                                DetailJsonReq detailJsonReq = map.get(key);
                                detailJsonReq.setNum(detailJsonReq.getNum()+1);
                                map.put(key,detailJsonReq);
                            }else {
                                DetailJsonReq detailJsonReq = new DetailJsonReq();
                                detailJsonReq.setNum(1);
                                detailJsonReq.setLocationName(one.getLocationName());
                                detailJsonReq.setLocationId(one.getLocationId());
                                detailJsonReq.setPrice(logDetail.getPrice());
                                detailJsonReq.setProperty(logDetail.getProperty());
                                map.put(key,detailJsonReq);
                            }
                        }
                        for (OrderDetail orderDetail:list) {
                            for (String key:map.keySet()) {
                                if (key.equals(orderDetail.getTypeId()+orderDetail.getSizeId()+orderDetail.getPrice()+orderDetail.getProperty())){
                                    orderDetail.setDetailJson(JSONObject.toJSONString(map.get(key)));
                                }
                            }
                        }
                        orderMainService.updateById(existOrder);
                        orderDetailService.updateBatchById(list);
                        MQDto mqDto = new MQDto();
                        mqDto.setApi("NormalToOrder");
                        mqDto.setType(existOrder.getOrderType().equals("in")?0:1);
                        List<String> collect = logDetailList
                                .stream().map(LogDetail::getInventoryId)
                                .collect(Collectors.toList());
                        mqDto.setIdList(collect);
                        if(existOrder.getOrderType().equals("in")){
                            MQ.SendMsg("orderExchange",existOrder.getEndOrgId().toString(),mqDto);
                        }else {
                            MQ.SendMsg("orderExchange",existOrder.getStartOrgId().toString(),mqDto);
                        }
                    }
                    //消息推送
                    MessageSendReq sendReq = new MessageSendReq();
                    String startUser= MapUtil.getStr(historicProcessInstance.getProcessVariables(),START_USER_INFO);
                    UserInfo user=  JSONObject.parseObject(startUser, UserInfo.class);
                    String Types= MapUtil.getStr(historicProcessInstance.getProcessVariables(),TYPE_ORDER);
                    sendReq.setReceiveUserIds(String.valueOf(user.getUserId()));

                    sendReq.setBizType("pass/"+Types);
                    sendReq.setBizId(Long.valueOf(processInstanceId));
                    if (Type.equals("stocktakeOrder"))//整理需要下发的消息
                    {
                        sendReq.setMsgTitle("盘点提醒");
                        sendReq.setMsgContent("【盘库单】已下发");
                    }
                    else
                    {
                        sendReq.setMsgTitle("您的审批已通过");
                        sendReq.setMsgContent("您提交的审批【"+mainProcess.getName()+"】已经通过");
                    }
                    sendReq.setPriority("0");
                    sendReq.setSendTime(DateTime.now());
                    messageApi.sendMessage(sendReq);
                    messageApi.queryCount(new MessageReq());
                    /*推送发送未读数量*/
                    MessageReq req1 = new MessageReq();
                    req1.setReadFlag(0);
                    req1.setReceiveUserId(user.getUserId());
                    Integer count1 = messageApi.queryCount(req1);
                    messageApi.pushMsgToUser(startUser,count1);
                }

            }
        }


    }

