package com.huigou.topsun.sap.processOutsource.application.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huigou.cache.SystemCache;
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.sap.common.HttpClient;
import com.huigou.topsun.sap.common.application.SapMutualEpLogApplication;
import com.huigou.topsun.sap.common.domain.SapResult;
import com.huigou.topsun.sap.permit.application.SapPermitApplication;
import com.huigou.topsun.sap.permit.vo.SapPermitItemVo;
import com.huigou.topsun.sap.permit.vo.SapPermitVo;
import com.huigou.topsun.sap.processOutsource.application.ProcessOutsourceApplication;
import com.huigou.topsun.sap.processOutsource.application.ProcessOutsourceMaterialApplication;
import com.huigou.topsun.sap.processOutsource.application.ProcessOutsourceOrderItemApplication;
import com.huigou.topsun.sap.processOutsource.domain.ProcessOutsource;
import com.huigou.topsun.sap.processOutsource.domain.ProcessOutsourceMaterial;
import com.huigou.topsun.sap.processOutsource.domain.ProcessOutsourceOrderItem;
import com.huigou.topsun.sap.processOutsource.domain.query.ProcessOutsourceQueryRequest;
import com.huigou.topsun.sap.processOutsource.domain.vo.ProcessOutsourceItemVo;
import com.huigou.topsun.sap.processOutsource.domain.vo.ProcessOutsourceVo;
import com.huigou.topsun.sap.processOutsource.repository.ProcessOutsourceOrderItemRepository;
import com.huigou.topsun.sap.processOutsource.repository.ProcessOutsourceRepository;
import com.huigou.topsun.sap.wasteSale.domain.WasteSale;
import com.huigou.topsun.sap.wasteSale.domain.WasteSaleItem;
import com.huigou.uasp.bmp.common.BizBillStatus;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.util.ClassHelper;
import com.huigou.util.DateUtil;
import com.huigou.util.StringUtil;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: xin.lu
 * @Date: 2024/08/02/10:01
 * @Description:
 */
@Service("processOutsourceApplication")
public class ProcessOutsourceApplicationImpl extends FlowBroker implements ProcessOutsourceApplication {
    @Autowired
    private ProcessOutsourceRepository processOutsourceRepository;
    @Autowired
    private ProcessOutsourceMaterialApplication processOutsourceMaterialApplication;
    @Autowired
    private ProcessOutsourceOrderItemApplication processOutsourceOrderItemApplication;
    @Autowired
    private HttpClient httpClient;
    @Autowired
    private SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private ProcessOutsourceOrderItemRepository processOutsourceOrderItemRepository;
    @Autowired
    private SapPermitApplication sapPermitApplication;
    @Autowired
    private TaskExecutor asyncWriteExecutor;

    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        ProcessOutsource processOutsource = getBizEntity(ProcessOutsource.class);
        if (processOutsource.isNew()) {
            processOutsource.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            processOutsource = (ProcessOutsource) commonDomainService.loadAndFillinProperties(processOutsource);
        }
        processOutsource = processOutsourceRepository.save(processOutsource);
        //保存组件明细
        List<ProcessOutsourceMaterial> processOutsourceMaterials = getBizEntities(ProcessOutsourceMaterial.class, "materialItems");
        processOutsourceMaterialApplication.saveProcessOutsourceMaterials(processOutsource.getId(),processOutsourceMaterials);

        //保存工单明细
        List<ProcessOutsourceOrderItem> orderItems = getBizEntities(ProcessOutsourceOrderItem.class, "orderItems");
        processOutsourceOrderItemApplication.saveProcessOutsourceOrderItems(processOutsource.getId(),orderItems);
        return processOutsource.getId();
    }


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

    /**
     * 获取任务标题
     *
     * @param bizId
     * @return
     */
    private String getApprovalSubjectName(String bizId) {
        ProcessOutsource processOutsource = this.processOutsourceRepository.findOne(bizId);
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", processOutsource.getFillinDate());
        //设置标题
        return String.format("%s-%s(%s)", "工序外协", processOutsource.getBillCode(), fillinDateStr);
    }

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(processOutsourceRepository.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();
        if (this.isApplyProcUnit(delegateTask) && this.getApprovalParameter().isAdvanceProcessAction()) {
            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(ProcessOutsource.class, bizId, status.getId());
    }

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        ProcessOutsource processOutsource = processOutsourceRepository.findOne(bizId);
        processOutsource.setStatusId(status.getId());
        //推送到SAP
        this.sendData(processOutsource);
        //创建放行条
        asyncWriteExecutor.execute(()->
                //创建放行条
                this.startSapPermit(processOutsource)
        );
        processOutsourceRepository.save(processOutsource);
    }

    /**
     * 转换成SAP JSON格式数据
     * @param processOutsource
     * @return
     */
    public void sendData(ProcessOutsource processOutsource){
        List<ProcessOutsourceOrderItem> orderItems = this.processOutsourceOrderItemApplication.findByProcessOutsourceId(processOutsource.getId());
        Set<String> lifnrSets = orderItems.stream().map(ProcessOutsourceOrderItem::getLifnr).collect(Collectors.toSet());
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        lifnrSets.forEach(lifnrSet ->{
            ProcessOutsourceVo processOutsourceVo = new ProcessOutsourceVo();
            processOutsourceVo.setBsart("ZNB3");
            processOutsourceVo.setBukrs("1000");
            processOutsourceVo.setEkorg("1000");
            processOutsourceVo.setEkgrp("003");
            processOutsourceVo.setLifnr(lifnrSet);
            List<ProcessOutsourceItemVo> itemVos = new ArrayList<>();
            int i = 10;
            for (ProcessOutsourceOrderItem processOutsourceOrderItem : orderItems) {
                //根据供应商封装一个ProcessOutsourceVo类
                if (lifnrSet.equals(processOutsourceOrderItem.getLifnr())){
                    //自动计数器，匹配条件为“如果之前状态为通过的申请中有相同工单+工序，则计数器+1，起始为1”
//                    List<ProcessOutsourceOrderItem> outsourceOrderItemList = processOutsourceOrderItemRepository
//                            .findByAufnrAndWempf(processOutsourceOrderItem.getAufnr(), processOutsourceOrderItem.getWempf());
//                    List<ProcessOutsourceOrderItem> collect = outsourceOrderItemList
//                            .stream()
//                            .filter(processOutsourceOrderItem1 -> StringUtil.isNotBlank(processOutsourceOrderItem1.getAblad()))
//                            .collect(Collectors.toList());
                    //手工填写，必须以“原工单”字段的内容作为开头部分；若值为空，传输“AUFNR”字段值
                    if (StringUtil.isNotBlank(processOutsourceOrderItem.getAblad())){
                        processOutsourceOrderItem.setAblad(processOutsourceOrderItem.getAufnr()+"-"+processOutsourceOrderItem.getAblad());
                    }else {
                        processOutsourceOrderItem.setAblad(processOutsourceOrderItem.getAufnr());
                    }
                    //ProcessOutsourceItemVo类组装数据
                    ProcessOutsourceItemVo processOutsourceItemVo = new ProcessOutsourceItemVo();
                    BeanUtil.copyProperties(processOutsourceOrderItem,processOutsourceItemVo);
                    processOutsourceItemVo.setWerks(processOutsource.getWerks());
                    //默认传F，隐藏
                    processOutsourceItemVo.setKnttp("F");
                    //默认传F00，隐藏
                    processOutsourceItemVo.setMatkl("F00");
                    //操作/活动编号 收货方同一个值
                    processOutsourceItemVo.setVornr(processOutsourceOrderItem.getWempf());
                    //日期转换
                    if (processOutsourceOrderItem.getEeind() != null){
                        String format = dateFormat.format(processOutsourceOrderItem.getEeind());
                        processOutsourceItemVo.setEeind(format);
                    }
                    //设置默认值
                    //processOutsourceVo.setPersonMemberName(processOutsource.getPersonMemberName());
                    //同一个供应商下的行项目序号
                    processOutsourceItemVo.setEbelp(String.valueOf(i));
                    processOutsourceOrderItem.setEbelp(String.valueOf(i));
                    itemVos.add(processOutsourceItemVo);
                    i = i + 10;
                }
            }
            processOutsourceVo.setItem(itemVos);

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("businessType", "工序外协申请");
            resultMap.put("businessId", processOutsource.getId());
            resultMap.put("parameter", JSON.toJSONString(processOutsourceVo));
            try {
                String url = "cud_po_zub/po_zub";
                //String url = SystemCache.getParameter("", String.class);
                String execute = httpClient.execute(processOutsourceVo, url);
                List<SapResult> resultList = JSONObject.parseArray(execute, SapResult.class);
                //TODO 待SAP返回数据结构
                SapResult sapResult = resultList.get(0);
                if (!"S".equals(sapResult.getTYPE())){
                    List<String> messages = resultList
                            .stream()
                            .map(SapResult::getMESSAGE).collect(Collectors.toList());
                    throw new RuntimeException("数据传输失败，"+ String.join("；",messages));
                } else {
                    resultMap.put("TYPE", sapResult.getTYPE());
                    resultMap.put("MESSAGE", sapResult.getMESSAGE());
                }
                orderItems.stream().forEach(orderItem->{
                    //根据供应商来匹配赋值采购订单号
                    if (lifnrSet.equals(orderItem.getLifnr())){
                        orderItem.setEbeln(sapResult.getMESSAGE_V1());
                        processOutsourceOrderItemRepository.save(orderItem);
                    }
                });
            } catch (IOException e) {
                resultMap.put("TYPE", "E");
                resultMap.put("MESSAGE", e.getMessage());
                throw new RuntimeException(e);
            }finally {
                sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
            }
        });
    }

    /**
     * 推送SAP成功后，自动创建放行条
     * @param processOutsource
     */
    public void startSapPermit(ProcessOutsource processOutsource){
        List<ProcessOutsourceMaterial> materialList = processOutsourceMaterialApplication.findByProcessOutsourceId(processOutsource.getId());
        SapPermitVo sapPermitVo = new SapPermitVo();
        sapPermitVo.setApplyPerson(processOutsource.getPersonMemberId());
        sapPermitVo.setApplyPersonName(processOutsource.getPersonMemberName());
        sapPermitVo.setDutyDepart(processOutsource.getDeptId());
        sapPermitVo.setDutyDepartName(processOutsource.getDeptName());
        sapPermitVo.setPermitDate(new Date());
        List<SapPermitItemVo> sapPermitItemVos = new ArrayList<>();
        for (ProcessOutsourceMaterial material : materialList) {
            SapPermitItemVo sapPermitItemVo = new SapPermitItemVo();
            sapPermitItemVo.setBelongings(material.getMaterialName());

            String remark="工序外协单:"+processOutsource.getBillCode();
            sapPermitItemVo.setRemark(remark);
            sapPermitItemVo.setQuantity(material.getNum());
            sapPermitItemVo.setUnit(material.getUnit());
            sapPermitItemVo.setUnitName(material.getUnitName());
            sapPermitItemVos.add(sapPermitItemVo);
        }
        sapPermitVo.setItemVos(sapPermitItemVos);
        //创建放行条
        sapPermitApplication.saveSapPermitVo(sapPermitVo);
    }

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

    /**
     * @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();
            ProcessOutsource processOutsource = processOutsourceRepository.findOne(bizId);
            processOutsource.setStatusId(BizBillStatus.APPLYING.getId());
            processOutsourceRepository.save(processOutsource);
        }
    }

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

    @Override
    public ProcessOutsource loadProcessOutsource(String id) {
        return processOutsourceRepository.findOne(id);
    }
    
    
}
