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

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huigou.cache.SystemCache;
import com.huigou.context.Operator;
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.sap.common.DefaultHttpClient;
import com.huigou.topsun.sap.common.application.SapMutualEpLogApplication;
import com.huigou.topsun.sap.inventoryRecord.application.InventoryRecordApplication;
import com.huigou.topsun.sap.inventoryRecord.application.InventoryRecordItemImApplication;
import com.huigou.topsun.sap.inventoryRecord.application.InventoryRecordItemWmApplication;
import com.huigou.topsun.sap.inventoryRecord.domain.InventoryRecord;
import com.huigou.topsun.sap.inventoryRecord.domain.InventoryRecordItemIm;
import com.huigou.topsun.sap.inventoryRecord.domain.InventoryRecordItemWm;
import com.huigou.topsun.sap.inventoryRecord.domain.query.InventoryRecordQueryRequest;
import com.huigou.topsun.sap.inventoryRecord.domain.vo.InventoryRecordVo;
import com.huigou.topsun.sap.inventoryRecord.repository.InventoryRecordRepository;
import com.huigou.topsun.sap.purchaseApproval.domain.SapPurchaseApproval;
import com.huigou.topsun.sap.purchaseApproval.domain.SapPurchaseApprovalItem;
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.util.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xin.lu
 * @Description: 库存记录应用服务
 * @date 2025/7/1710:24
 */
@Service("inventoryRecordApplication")
public class InventoryRecordApplicationImpl extends FlowBroker implements InventoryRecordApplication {
    @Autowired
    private InventoryRecordRepository inventoryRecordRepository;
    @Autowired
    private InventoryRecordItemImApplication inventoryRecordItemImApplication;
    @Autowired
    private InventoryRecordItemWmApplication inventoryRecordItemWmApplication;
    @Autowired
    private DefaultHttpClient defaultHttpClient;
    @Autowired
    private SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private OperatorApplication operatorApplication;
    @Autowired
    private MannualStartWorkApplication mannualStartWorkApplication;

    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        InventoryRecord inventoryRecord = getBizEntity(InventoryRecord.class);
        if (inventoryRecord.isNew()) {
            inventoryRecord.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            inventoryRecord = (InventoryRecord) commonDomainService.loadAndFillinProperties(inventoryRecord);
        }
        inventoryRecord = inventoryRecordRepository.save(inventoryRecord);
        //保存wm盘点数据
        List<InventoryRecordItemWm> wmItems = getBizEntities(InventoryRecordItemWm.class, "wmItems");
        if (!CollectionUtils.isEmpty(wmItems)){
            inventoryRecordItemWmApplication.saveInventoryRecordItemWms(inventoryRecord.getId(),wmItems);
        }

        //保存im盘点数据
        List<InventoryRecordItemIm> imItems = getBizEntities(InventoryRecordItemIm.class, "imItems");
        if (!CollectionUtils.isEmpty(imItems)){
            inventoryRecordItemImApplication.saveInventoryRecordItemIms(inventoryRecord.getId(),imItems);
        }

        return inventoryRecord.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) {
        InventoryRecord inventoryRecord = this.inventoryRecordRepository.findOne(bizId);
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", inventoryRecord.getFillinDate());
        //设置标题
        return String.format("%s-%s(%s)", "库存盘点" , inventoryRecord.getBillCode(), fillinDateStr);
    }

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(inventoryRecordRepository.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();
        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(InventoryRecord.class, bizId, status.getId());
    }

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        //取消待办任务办结提醒
        //super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        InventoryRecord inventoryRecord = inventoryRecordRepository.findOne(bizId);
        inventoryRecord.setStatusId(status.getId());
        inventoryRecordRepository.save(inventoryRecord);

        //推送审批结果
        sendSapData(inventoryRecord,"Y");
    }

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

    /**
     * @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();
            InventoryRecord inventoryRecord = inventoryRecordRepository.findOne(bizId);
            inventoryRecord.setStatusId(BizBillStatus.APPLYING.getId());
            inventoryRecordRepository.save(inventoryRecord);
            //推送审批结果
            sendSapData(inventoryRecord,"N");
        }
    }

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

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

    @Override
    public InventoryRecord loadInventoryRecord(String id) {
        return inventoryRecordRepository.findOne(id);
    }

    @Override
    public List<Map<String,Object>> saveInventoryRecordVo(List<InventoryRecordVo> inventoryRecordVos) {
        String ztype = inventoryRecordVos.get(0).getZtype();
        String uname = inventoryRecordVos.get(0).getUname();
        //根据SAP传过来的操作人编码，映射流程发起人
        Org org = orgApplication.loadMainOrgByLoginName(uname);
        if (ObjectUtil.isNull(org)){
            String acceptPersonCode = SystemCache.getParameter("acceptPersonCode", String.class);
            org = orgApplication.loadMainOrgByLoginName(acceptPersonCode);
        }
        Operator operator = operatorApplication.createOperatorByPersonMemberId(org.getId());
        ThreadLocalUtil.putOperator(operator);
        Set<String> ivnumSets = new HashSet<>();
        //如果是WM，根据盘点记录号进行分组统计
        if ("WM".equals(ztype)){
            ivnumSets = inventoryRecordVos
                    .stream()
                    .map(InventoryRecordVo::getIvnum)
                    .collect(Collectors.toSet());
        }
        //如果是IM，根据库存盘点凭证分组统计
        if ("IM".equals(ztype)){
            ivnumSets = inventoryRecordVos
                    .stream()
                    .map(InventoryRecordVo::getIblnr)
                    .collect(Collectors.toSet());
        }
        List<Map<String,Object>> mapList = new ArrayList<>();
        for (String ivnum : ivnumSets) {
            List<InventoryRecordVo> recordVoList = inventoryRecordVos
                    .stream()
                    .filter(inventoryRecordVo -> "WM".equals(ztype) ? ivnum.equals(inventoryRecordVo.getIvnum()) : ivnum.equals(inventoryRecordVo.getIblnr()))
                    .collect(Collectors.toList());
            InventoryRecord inventoryRecord = new InventoryRecord();
            Map<String,Object> map = new HashMap<>();
            inventoryRecord.setZtype(ztype);
            //发起流程
            String inventoryRecordId = mannualStartWorkApplication.startWorkflow(inventoryRecord,PROCESS_DEFINITION_KEY,"inventoryRecord");
            if ("WM".equals(ztype)){
                inventoryRecordItemWmApplication.saveInventoryRecordWmVo(recordVoList,inventoryRecordId);
            }
            if ("IM".equals(ztype)){
                inventoryRecordItemImApplication.saveInventoryRecordImVo(recordVoList,inventoryRecordId);
            }
            SDO sdo = ThreadLocalUtil.getVariable(Constants.SDO, SDO.class);
            String billCode = sdo.getString("billCode");
            map.put("IVNUM",ivnum);
            map.put("ZBPMID",billCode);
            mapList.add(map);
        }
        return mapList;
    }

    /**
     * 远程调用sap接口，传递数据
     */
    public void sendSapData(InventoryRecord inventoryRecord, String flag) {
        Map<String,Object> param = new HashMap<>();
        if ("wm".equals(inventoryRecord.getZtype())){
            List<InventoryRecordItemWm> inventoryRecordItemWms = inventoryRecordItemWmApplication.queryInventoryRecordItemWms(inventoryRecord.getId());
            String ivnum = inventoryRecordItemWms.get(0).getIvnum();
            param.put("NVERS",inventoryRecordItemWms.get(0).getNvers());
            param.put("IVNUM",ivnum);
        }
        if ("IM".equals(inventoryRecord.getZtype())){
            List<InventoryRecordItemIm> inventoryRecordItemIms = inventoryRecordItemImApplication.queryInventoryRecordItemIms(inventoryRecord.getId());
            String iblnr = inventoryRecordItemIms.get(0).getIblnr();
            param.put("IBLNR",iblnr);
        }
        param.put("ZBPMID",inventoryRecord.getBillCode());
        param.put("ZTYPE",inventoryRecord.getZtype());
        param.put("ZSP",flag);

        ObjectMapper objectMapper = new ObjectMapper();
        String url = "mm_inventory";
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("businessType", "库存盘点");
        resultMap.put("businessId", inventoryRecord.getId());
        resultMap.put("parameter", JSON.toJSONString(param));
        String type = "";
        String message = "";
        try {
            String result = defaultHttpClient.execute(param, url);
            List<Map<String, Object>> resultList = objectMapper.readValue(result, new TypeReference<List<Map<String, Object>>>() {});
            Map<String, Object> backMap = resultList.get(0);
            type = (String) backMap.get("TYPE");
            message = (String) backMap.get("MESSAGE");
            if (!"S".equals(type)) {
                throw new RuntimeException("数据传输失败，请稍后手动重试！"+message);
            } else {
                resultMap.put("TYPE", type);
                resultMap.put("MESSAGE", message);
            }
        } catch (Exception e) {
            resultMap.put("TYPE", "E");
            resultMap.put("MESSAGE", e.getMessage());
            throw new RuntimeException("数据传输失败请检查数据后重试！"+e.getMessage());
        }finally {
            inventoryRecord.setType(type);
            inventoryRecord.setMessage(message);
            inventoryRecordRepository.save(inventoryRecord);
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }

}
