package com.huigou.topsun.ep.order.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.common.CommonUtils;
import com.huigou.topsun.ep.change.application.EpChangeFormApplication;
import com.huigou.topsun.ep.order.application.EpSaleOrderApplication;
import com.huigou.topsun.ep.order.domain.EpSaleOrderItem;
import com.huigou.topsun.ep.order.domain.vo.EpSaleOrderItemVo;
import com.huigou.topsun.ep.order.domain.vo.EpSaleOrderVo;
import com.huigou.topsun.ep.order.repository.EpSaleOrderRepository;
import com.huigou.topsun.sap.common.HttpClient;
import com.huigou.topsun.ep.order.application.EpSaleOrderItemApplication;
import com.huigou.topsun.ep.order.domain.EpSaleOrder;
import com.huigou.topsun.ep.order.domain.query.EpSaleOrderQueryRequest;
import com.huigou.topsun.sap.common.application.SapMutualEpLogApplication;
import com.huigou.topsun.sap.common.domain.EpResult;
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.repository.ProcUnitHandlerRepository;
import com.huigou.util.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.runtime.ProcessInstance;
import org.krysalis.barcode4j.HumanReadablePlacement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: xin.lu
 * @Date: 2024/03/12/19:17
 * @Description:
 */
@Service("epSaleOrderApplication")
public class EpSaleOrderApplicationImpl extends FlowBroker implements EpSaleOrderApplication {
    @Autowired
    private EpSaleOrderRepository epSaleOrderRepository;
    @Autowired
    private EpSaleOrderItemApplication epSaleOrderItemApplication;
    @Autowired
    private HttpClient httpClient;
    @Resource
    private WorkflowApplication workflowApplication;
    @Resource
    private OperatorApplication operatorApplication;
    @Autowired
    SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private MannualStartWorkApplication mannualStartWorkApplication;

    @Autowired
    private ProcUnitHandlerRepository procUnitHandlerRepository;
    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        EpSaleOrder epSaleOrder = getBizEntity(EpSaleOrder.class);
        if (epSaleOrder.isNew()) {
            epSaleOrder.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            epSaleOrder = (EpSaleOrder) commonDomainService.loadAndFillinProperties(epSaleOrder);
        }
        epSaleOrder = epSaleOrderRepository.save(epSaleOrder);
        List<EpSaleOrderItem> epSaleOrderItems = getBizEntities(EpSaleOrderItem.class, "epSaleOrderItems");
        epSaleOrderItemApplication.saveEpSaleOrderItems(epSaleOrder.getId(),epSaleOrderItems);
        return epSaleOrder.getId();
    }
    
    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        SDO sdo = ThreadLocalUtil.getVariable(Constants.SDO,SDO.class);
        return sdo.getProperties();
    }

    /**
     * 流程撤销事件
     **/
    @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();
        updateStatus(bizId, BizBillStatus.APPROVING);
    }

    /**
     * 回收事件
     **/
    @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
    protected void updateStatus(String bizId, BizBillStatus status) {
        Assert.hasText(bizId, CommonDomainConstants.ID_NOT_BLANK);
        this.commonDomainService.updateStatus(EpSaleOrder.class, bizId, status.getId());
    }

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        //super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        EpSaleOrder epSaleOrder = epSaleOrderRepository.findOne(bizId);
        epSaleOrder.setStatusId(status.getId());
        epSaleOrderRepository.save(epSaleOrder);
        this.feedBackSaleOrder(epSaleOrder,"1");
    }

    @Override
    protected void onAbortProcessInstance(DelegateExecution delegateExecution) {
        super.onAbortProcessInstance(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        EpSaleOrder epSaleOrder = epSaleOrderRepository.findOne(bizId);
        epSaleOrder.setStatusId(BizBillStatus.ABORTED.getId());
        epSaleOrderRepository.save(epSaleOrder);

        this.feedBackSaleOrder(epSaleOrder,"5");
    }

    /**
     * @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();
            EpSaleOrder epSaleOrder = epSaleOrderRepository.findOne(bizId);
            epSaleOrder.setStatusId(BizBillStatus.APPLYING.getId());
            epSaleOrderRepository.save(epSaleOrder);
            this.feedBackSaleOrder(epSaleOrder,"0");
            //回退后终止流程
//            DelegateExecution execution = delegateTask.getExecution();
//            this.onAbortProcessInstance(execution);
//            this.feedBackSaleOrder(epSaleOrder,"0");
        }
    }

    @Override
    protected void setTaskDescription(DelegateTask delegateTask) {
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        delegateTask.setDescription(this.getApprovalSubjectName(bizId));
    }

    /**
     * 获取任务标题
     *
     * @param bizId
     * @return
     */
    private String getApprovalSubjectName(String bizId) {
        EpSaleOrder epSaleOrder = this.epSaleOrderRepository.findOne(bizId);
        String vbeln = this.getBizAndApprovalData().getString("vbeln");
        if (StringUtil.isBlank(vbeln)){
            List<EpSaleOrderItem> itemList = epSaleOrderItemApplication.findByEpSaleOrderId(bizId);
            Set<String> vbelns = itemList.stream().map(EpSaleOrderItem::getVbeln).collect(Collectors.toSet());
            vbeln = String.join(",", vbelns);
        }
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", epSaleOrder.getFillinDate());
        //设置标题
        return String.format("%s-%s(%s)", epSaleOrder.getKunnr(), vbeln, fillinDateStr);
    }
    
    
    @Override
    public EpSaleOrder findEpSaleOrderById(String id) {
        return epSaleOrderRepository.findOne(id);
    }

    @Override
    public void deleteEpSaleOrderById(List<String> ids) {
        ids.forEach(id->{
            epSaleOrderRepository.delete(id);
        });
    }

    @Override
    public void updateEpSaleOrder(EpSaleOrder epSaleOrder) {
        epSaleOrderRepository.save(epSaleOrder);
    }

    @Override
    public EpSaleOrder saveEpSaleOrder(EpSaleOrder epSaleOrder) {
        return epSaleOrderRepository.save(epSaleOrder);
    }

    @Override
    public Map<String, Object> slicedEpSaleOrderList(EpSaleOrderQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "epSaleOrder");
        QueryModel queryModel = this.sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest);
        queryModel.putDictionary("status",BizBillStatus.getMap());
        queryModel.addCriteria(" order by bill_code desc ");
        Map<String, Object> map = this.sqlExecutorDao.executeSlicedQuery(queryModel);
        return map;
    }

    @Override
    @Transactional
    public void saveEpSaleOrderVo(List<EpSaleOrderVo> epSaleOrderVos) {
        for (EpSaleOrderVo epSaleOrderVo : epSaleOrderVos) {
            EpSaleOrder epSaleOrder = new EpSaleOrder();
            BeanUtil.copyProperties(epSaleOrderVo,epSaleOrder);

            //初始化用户信息
            String personCode = epSaleOrderVos.get(0).getPersonCode();
            Org createorg = orgApplication.loadMainOrgByLoginName(personCode);
            if (createorg == null){
                throw new RuntimeException("未找到编码为：" + personCode + " 的人员");
            }
//            QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "loadPersonMemberId");
//            String personMemberId = this.sqlExecutorDao.queryToString(queryDescriptor.getSql(), personCode);
//            if (StringUtil.isBlank(personMemberId)){
//                throw new RuntimeException("未找到编码为：" + personCode + " 的人员");
//            }

            //String createdById =  SystemCache.getParameter("adminPersonId", String.class);
            Operator operator = operatorApplication.createOperatorByPersonMemberId(createorg.getId());
            //SDO sdo = new SDO();
            //localSdo.setOperator(operator);
            ThreadLocalUtil.putOperator(operator);
            epSaleOrder.setDefaultValues(new OrgUnit(operator.getFullId(), operator.getFullName()));
            //退货退款和换货退回的才这样改：两个电话改成联系人和联系电话，不用加字段
            //其他类型订单都是取跟单员的电话，没有带出来就是空的，可以继续审批。
            if (!"ZRE1".equals(epSaleOrderVo.getOrderType()) && !"ZHR".equals(epSaleOrderVo.getOrderType())){
                epSaleOrder.setTelPhoneLong(createorg.getPerson().getMobilePhone());//长号取移动电话
                epSaleOrder.setTelPhoneShort(createorg.getPerson().getOfficePhone());//短号取办公电话
            }
            Map<String, Object> formData = BeanUtil.beanToMap(epSaleOrder);
            List<EpSaleOrderItemVo> epSaleOrderItemVos = epSaleOrderVo.getEpSaleOrderItemVos();
            Set<String> vbelns = epSaleOrderItemVos.stream().map(EpSaleOrderItemVo::getVbeln).collect(Collectors.toSet());
            String vbeln = String.join(",", vbelns);
            formData.put("vbeln",vbeln);
            //退货/退换货	跟单员	一级	二级	三级
            //业务一课	 	        张小英	胡德军
            //业务二课		        封献	张小英	胡德军
            //外贸课		            赵儒洋	张小英	胡德军
            //
            //
            //免费订单	            跟单员	一级	            二级	三级	四级
            //小于等于50块		            主任和课长、组长
            //大于50小于等于300		        主任和课长、组长	    张小英
            //大于300小于等于1000		    主任和课长、组长	    张小英	胡德军
            //大于1000		                主任和课长、组长	    张小英	胡德军	副总裁（大苗总）

            //跟单员信息
            String merchandiser = epSaleOrderItemVos.get(0).getMerchandiser();
            Org org = orgApplication.loadMainOrgByLoginName(merchandiser);
            if (org == null){
                throw new RuntimeException("未找到编码为：" + merchandiser + " 的跟单员信息");
            }
            formData.put("deptCode",org.getDeptCode());
            List<EpSaleOrderItem> epSaleOrderItems = new ArrayList<>();
            BigDecimal amount = BigDecimal.ZERO;
            for (EpSaleOrderItemVo epSaleOrderItemVo : epSaleOrderItemVos) {
                EpSaleOrderItem epSaleOrderItem = new EpSaleOrderItem();
                BeanUtil.copyProperties(epSaleOrderItemVo,epSaleOrderItem);
                amount = amount.add(epSaleOrderItem.getAmount());
                epSaleOrderItem.setMerchandiserName(org.getName());
                epSaleOrderItem.setMerchandiser(org.getCode());
                String s = epSaleOrderItem.getMatnr().replaceAll("^(0+)", "");
                epSaleOrderItem.setMatnr(s);
                epSaleOrderItems.add(epSaleOrderItem);
            }
            formData.put("amount",amount);//总金额
            formData.put("merchandiser",org.getCode());
            epSaleOrder.setMerchandiser(org.getCode());
            String bizId =mannualStartWorkApplication.startWorkflow(formData,PROCESS_DEFINITION_KEY,"epSaleOrder");

            epSaleOrder.setId(bizId);
            epSaleOrder.setStatusId(BizBillStatus.APPROVING.getId()); //lxh  08.01
          //  epSaleOrder.setStatusId(BizBillStatus.APPLYING.getId());
            epSaleOrder = epSaleOrderRepository.save(epSaleOrder);

            this.epSaleOrderItemApplication.saveEpSaleOrderItems(epSaleOrder.getId(),epSaleOrderItems);
            }
        }

    @Override
    public Map<String, Object> print(String id) {
        EpSaleOrder epSaleOrder = epSaleOrderRepository.findOne(id);
        Map<String, Object> map = ClassHelper.toMap(epSaleOrder);
        //时间
        Date fillinDate = epSaleOrder.getFillinDate();
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd", fillinDate);
        map.put("fillinDate",fillinDateStr);
        //明细数据
        List<EpSaleOrderItem> orderItemList = epSaleOrderItemApplication.findByEpSaleOrderId(epSaleOrder.getId());
        //合计数量
        BigDecimal total = orderItemList.stream()
                .map(EpSaleOrderItem::getKwmeng)
                .reduce(BigDecimal.ZERO,BigDecimal::add);
        //品牌
        String mvgr1 = orderItemList.get(0).getMvgr1();
        map.put("mvgr1",mvgr1);
        map.put("total",total);
        map.put("itemList",orderItemList);

        //核准人、审核人
        List<ProcUnitHandler> handlerList = procUnitHandlerRepository.findByBizId(id);
        ProcUnitHandler procUnitHandler = handlerList
                .stream()
                .max(Comparator.comparing(ProcUnitHandler::getGroupId))
                .get();
        map.put("lastApproval",procUnitHandler.getHandlerName());
        Set<String> stringSet = handlerList
                .stream()
                .filter(item -> !item.getHandlerName().equals(procUnitHandler.getHandlerName()))
                .map(ProcUnitHandler::getHandlerName)
                .collect(Collectors.toSet());
        map.put("approvals",String.join(",",stringSet));
        //条形码
        File file = new File(epSaleOrder.getBillCode()+".png");
        if(!file.exists()) {
            String IMG_TYPE_PNG = "image/png";
            try {
                map.put("barCode", CommonUtils.genBarCode128(epSaleOrder.getBillCode(), IMG_TYPE_PNG, file,128,10, HumanReadablePlacement.HRP_NONE));
            } catch (IOException e) {
                throw new RuntimeException("条形码生成失败：" + e.getMessage());
            }
        } else {
            map.put("barCode",file);
        }
        return map;
    }

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

    public void feedBackSaleOrder(EpSaleOrder epSaleOrder,String state){
        List<EpSaleOrderItem> orderItemList = epSaleOrderItemApplication.findByEpSaleOrderId(epSaleOrder.getId());
        Map<String,Object> map = new HashMap<>();
        map.put("state",state);
        Set<String> saleOrderNos = new HashSet<>();
        for (EpSaleOrderItem epSaleOrderItem : orderItemList) {
            saleOrderNos.add(epSaleOrderItem.getVbeln());
        }
        map.put("saleOrderNos",saleOrderNos);
        //日志记录
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String execute = httpClient.executeForEp(map, "od/saleOrder/auditedResult");
            EpResult epResult = JSONObject.parseObject(execute, EpResult.class);
            resultMap.put("TYPE", epResult.getCode());
            resultMap.put("message", epResult.getMsg());
            if (!"200".equals(epResult.getCode())){
                throw new RuntimeException("数据传输失败，"+ epResult.getMsg());
            }
            epSaleOrder.setCode(epResult.getCode());
            epSaleOrder.setMsg(epResult.getMsg());
            epSaleOrderRepository.save(epSaleOrder);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            resultMap.put("businessType", epSaleOrder.getOrderTypeName());
            resultMap.put("businessId", epSaleOrder.getId());
            resultMap.put("parameter", JSON.toJSONString(map));
            resultMap.put("sequence", resultMap.get("row"));
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }
}
