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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.dataPermission.application.DataPermissionApplication;
import com.huigou.topsun.sap.common.HttpClient;
import com.huigou.topsun.sap.common.application.SapMutualEpLogApplication;
import com.huigou.topsun.sap.purchase.application.SapPurchaseApplication;
import com.huigou.topsun.sap.purchase.application.SapPurchaseItemApplication;
import com.huigou.topsun.sap.purchase.domain.SapPurchase;
import com.huigou.topsun.sap.purchase.domain.SapPurchaseItem;
import com.huigou.topsun.sap.purchase.domain.query.SapPurchaseQueryRequest;
import com.huigou.topsun.sap.purchase.domain.vo.SapPurchaseItemDto;
import com.huigou.topsun.sap.purchase.domain.vo.SapPurchaseItemVo;
import com.huigou.topsun.sap.purchase.domain.vo.SapPurchaseVo;
import com.huigou.topsun.sap.purchase.repository.SapPurchaseRepository;
import com.huigou.topsun.sap.common.domain.SapResult;
import com.huigou.topsun.sap.purchaseApproval.application.SapPurchaseApprovalApplication;
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.ClassHelper;
import com.huigou.util.Constants;
import com.huigou.util.DateUtil;
import com.huigou.util.SDO;
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 javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: xin.lu
 * @Date: 2023/12/27/10:38
 * @Description:
 */
@Service("sapPurchaseApplication")
public class SapPurchaseApplicationImpl extends FlowBroker implements SapPurchaseApplication {
    @Resource
    private SapPurchaseRepository sapPurchaseRepository;
    @Resource
    private SapPurchaseItemApplication sapPurchaseItemApplication;
    @Resource
    private HttpClient httpClient;
    @Autowired
    SapMutualEpLogApplication sapMutualEpLogApplication;

    @Autowired
    private MannualStartWorkApplication mannualStartWorkApplication;
    @Autowired
    private DataPermissionApplication dataPermissionApplication;
    @Autowired
    private OperatorApplication operatorApplication;
    @Autowired
    private SapPurchaseApprovalApplication sapPurchaseApprovalApplication;

    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        SapPurchase sapPurchase = getBizEntity(SapPurchase.class);
        if (sapPurchase.isNew()) {
            sapPurchase.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            sapPurchase = (SapPurchase) commonDomainService.loadAndFillinProperties(sapPurchase);
        }
        List<SapPurchaseItem> sapPurchaseItems = getBizEntities(SapPurchaseItem.class, "sapPurchaseItems");
        Set<String> collect = sapPurchaseItems
                .stream()
                .map(SapPurchaseItem::getKostl)
                .collect(Collectors.toSet());
        String kostl = String.join(",", collect);
        sapPurchase.setKostl(kostl);
        sapPurchase = sapPurchaseRepository.save(sapPurchase);
        sapPurchaseItemApplication.saveSapPurchaseItems(sapPurchase.getId(),sapPurchaseItems);

        /*List<SapPurchaseVo> purchaseVoList = this.getSapPurchaseVoJson(sapPurchase);
        try {
            String url = SystemCache.getParameter("sap.purchase.url", String.class);
            String execute = httpClient.execute(purchaseVoList, url);
            System.out.println("返回结果："+execute);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }*/
        return sapPurchase.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) {
        SapPurchase sapPurchase = this.sapPurchaseRepository.findOne(bizId);
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", sapPurchase.getFillinDate());
        String title = "";
        if ("update".equals(sapPurchase.getRevokeType())){
            title = "撤审修改-";
        }else if ("close".equals(sapPurchase.getRevokeType())){
            title = "撤审关单-";
        }
        //设置标题
        switch (sapPurchase.getBsart()){
            case "ZNE1"://固定资产采购申请
                return String.format("%s-%s(%s)", title+"固定资产采购申请", sapPurchase.getBillCode(), fillinDateStr);
            case "ZFW"://服务类采购申请
                return String.format("%s-%s(%s)", title+"服务类采购申请", sapPurchase.getBillCode(), fillinDateStr);
            case "ZNE2"://非资产类消耗性采购申请
                return String.format("%s-%s(%s)", title+"非资产类消耗性采购申请", sapPurchase.getBillCode(), fillinDateStr);
        }
        return null;
    }

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

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        //super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        SapPurchase sapPurchase = sapPurchaseRepository.findOne(bizId);
        sapPurchase.setStatusId(status.getId());
        sapPurchase.setFrgdt(new Date());
        if ("close".equals(sapPurchase.getRevokeType())){
            this.closeSapPurchase(sapPurchase);
        }else {
            this.createdSapPurchase(sapPurchase);
        }
    }

    public void createdSapPurchase(SapPurchase sapPurchase){
        SapPurchaseVo sapPurchaseVo = this.getSapPurchaseVoJson(sapPurchase);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("businessType", "采购申请创建");
        resultMap.put("businessId", sapPurchase.getId());
        resultMap.put("parameter", JSON.toJSONString(sapPurchaseVo));
        try {
            String url = SystemCache.getParameter("sap.purchase.url", String.class);
            String execute = httpClient.execute(sapPurchaseVo, url);
            List<SapResult> resultList = JSONObject.parseArray(execute, SapResult.class);
            SapResult sapResult = resultList.get(0);
            resultMap.put("TYPE", sapResult.getTYPE());
            resultMap.put("MESSAGE", sapResult.getMESSAGE());
            if (!"S".equals(sapResult.getTYPE())){
                List<String> messages = resultList
                        .stream()
                        .map(SapResult::getMESSAGE).collect(Collectors.toList());
                throw new RuntimeException("数据传输失败，"+ String.join("；",messages));
            }
            sapPurchase.setBanfn(sapResult.getMESSAGE_V1());//SAP采购申请编号
            sapPurchase.setType(sapResult.getTYPE());
            sapPurchase.setMessage(sapResult.getMESSAGE());
            sapPurchaseRepository.save(sapPurchase);
        } catch (IOException e) {
            resultMap.put("TYPE", "E");
            resultMap.put("MESSAGE", e.getMessage());
            throw new RuntimeException(e);
        }finally {
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }

    public void closeSapPurchase(SapPurchase sapPurchase){
        List<SapPurchaseItem> sapPurchaseItemList = this.sapPurchaseItemApplication.findBySapPurchaseId(sapPurchase.getId());
        List<Map<String,Object>> paramList= new ArrayList<>();
        for (SapPurchaseItem sapPurchaseItem : sapPurchaseItemList) {
            Map<String,Object> paramItem = new HashMap<>();
            paramItem.put("banfn",sapPurchase.getBanfn());
            paramItem.put("BEDNR",sapPurchase.getBillCode());
            paramItem.put("frgkz","10");
            paramItem.put("bnfpo",sapPurchaseItem.getBnfpo());
            paramItem.put("flag","N");
            paramItem.put("status",0);
            paramItem.put("ELIKZ", "X");
            paramList.add(paramItem);
        }
        Map<String,Object> param = new HashMap<>();
        param.put("MODE","PR");
        param.put("DATA",paramList);

        ObjectMapper objectMapper = new ObjectMapper();
        String url = "pass_approval/approval";
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("businessType", "采购申请关单");
        resultMap.put("businessId", sapPurchase.getId());
        resultMap.put("parameter", JSON.toJSONString(param));
        String type = "";
        String message = "";
        try {
            String result = httpClient.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 {
            sapPurchase.setType(type);
            sapPurchase.setMessage(message);
            sapPurchaseRepository.save(sapPurchase);
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }

    /**
     * 转换成SAP JSON格式数据
     * @param sapPurchase
     * @return
     */
    public SapPurchaseVo getSapPurchaseVoJson(SapPurchase sapPurchase){
        List<SapPurchaseItem> sapPurchaseItemList = this.sapPurchaseItemApplication.findBySapPurchaseId(sapPurchase.getId());
        List<SapPurchaseItemVo> sapPurchaseItemVos = new ArrayList<>();
        SapPurchaseVo sapPurchaseVo = new SapPurchaseVo();
        sapPurchaseVo.setBsart(sapPurchase.getBsart());
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        sapPurchaseItemList.forEach(sapPurchaseItem -> {
            SapPurchaseItemVo sapPurchaseItemVo = new SapPurchaseItemVo();
            BeanUtil.copyProperties(sapPurchaseItem,sapPurchaseItemVo);
            sapPurchaseItemVo.setKnttp(sapPurchase.getKnttp());
            sapPurchaseItemVo.setBillCode(sapPurchase.getBillCode());
            sapPurchaseItemVo.setErnam(sapPurchase.getPersonMemberName());
//            if (sapPurchaseItem.getBadat() != null){
//                String format = dateFormat.format(sapPurchaseItem.getBadat());
//                sapPurchaseItemVo.setBadat(format);
//            }
            sapPurchaseItemVo.setBadat(dateFormat.format(new Date()));
//            if (sapPurchaseItem.getErdat()!=null){
//                String format = dateFormat.format(sapPurchaseItem.getErdat());
//                sapPurchaseItemVo.setErdat(format);
//            }
            sapPurchaseItemVo.setErdat(dateFormat.format(new Date()));
            if (sapPurchase.getFrgdt()!=null){
                String format = dateFormat.format(sapPurchase.getFrgdt());
                sapPurchaseItemVo.setFrgdt(format);
            }
            if (sapPurchaseItem.getLfdat()!=null){
                String format = dateFormat.format(sapPurchaseItem.getLfdat());
                sapPurchaseItemVo.setLfdat(format);
            }
            if ("A".equals(sapPurchase.getKnttp())){
                //anln3用于接受固定资产编号
                sapPurchaseItemVo.setAnln3(sapPurchaseItemVo.getAnln1());
                sapPurchaseItemVo.setAnln1(null);
                //多个资产号传1
                if (sapPurchaseItemVo.getAnln3().contains(",")){
                    sapPurchaseItemVo.setVrtkz("1");
                }else {
                    //1一个资产号传空
                    sapPurchaseItemVo.setVrtkz("");
                }
            }
            //如果是关单，传X
            if ("close".equals(sapPurchase.getRevokeType())){
                sapPurchaseItemVo.setElikz("X");
            }
            sapPurchaseItemVos.add(sapPurchaseItemVo);
        });
        sapPurchaseVo.setItemVos(sapPurchaseItemVos);
        /*ObjectMapper objectMapper = new ObjectMapper();
        String returnJson = null;
        try {
            returnJson = objectMapper.writeValueAsString(sapPurchaseVoList);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }*/
        return sapPurchaseVo;
    }

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

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

    @Override
    public Map<String, Object> slicedSapPurchaseList(SapPurchaseQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "sapPurchaseList");
        QueryModel queryModel = this.sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest);
        queryModel.putDictionary("status", BizBillStatus.getMap());
//        StringBuffer sb = new StringBuffer(queryModel.getSql());
//        dataPermissionApplication.getDataManagePermission(sb);
//        queryModel.setSql(sb.toString());
        return this.sqlExecutorDao.executeSlicedQuery(queryModel);
    }

    @Override
    public SapPurchase loadSapPurchase(String id) {
        return sapPurchaseRepository.findOne(id);
    }

    @Override
    public  String revokeApproval(String id,String revokeReason,String revokeType){
        SapPurchase sapPurchase = this.sapPurchaseRepository.findOne(id);
        //验证采购申请单是否生成了采购订单
        String result = this.sapPurchaseApprovalApplication.checkOrderByPurchaseNo(sapPurchase.getBanfn());
        //Y是可以提交撤审，N是查询到有对应的采购订单，不可以提交撤审
        if ("N".equals(result)){
            throw new RuntimeException("采购申请单已生成采购订单，不能撤销！");
        }
        if (sapPurchase.getStatusId()!=BizBillStatus.COMPLETED.getId()){
            throw new RuntimeException("审批完成的单据才能撤销！");
        }
        sapPurchase.setStatusId(BizBillStatus.ABORTED.getId());
        sapPurchaseRepository.save(sapPurchase);
        List<SapPurchaseItem> sapPurchaseItemList=this.sapPurchaseItemApplication.findBySapPurchaseId(id);
        //发起流程
        SapPurchase newSapPurchase=new SapPurchase();
        ClassHelper.copyProperties(sapPurchase,newSapPurchase);
        newSapPurchase.setId("");
        newSapPurchase.setBillCode("");
        newSapPurchase.setRevokeReason(revokeReason);
        newSapPurchase.setRevokeType(revokeType);
        newSapPurchase.setType(null);
        newSapPurchase.setMessage(null);
        String pId=mannualStartWorkApplication.startWorkflow(newSapPurchase,PROCESS_DEFINITION_KEY,"sapPurchase");
        newSapPurchase=this.sapPurchaseRepository.findOne(pId);


        List<SapPurchaseItem> newSapPurchaseItemList=new ArrayList<>();
        for (SapPurchaseItem sapPurchaseItem:sapPurchaseItemList){
            SapPurchaseItem newSapPurchaseItem=new SapPurchaseItem();
            ClassHelper.copyProperties(sapPurchaseItem,newSapPurchaseItem);
            newSapPurchaseItem.setId("");
            newSapPurchaseItemList.add(newSapPurchaseItem);
        }
        sapPurchaseItemApplication.saveSapPurchaseItems(newSapPurchase.getId(),newSapPurchaseItemList);

        return newSapPurchase.getId();
    }

    @Override
    public SapPurchase saveEPPurchaseItem(SapPurchase sapPurchase, SapPurchaseItemDto sapPurchaseItemDto) {
        //创建主表
        //根据SAP传过来的创建人编码，映射流程发起人
        String afnam = sapPurchaseItemDto.getAfnam();
        Org org = orgApplication.loadMainOrgByLoginName(afnam);
        String acceptPersonCode = SystemCache.getParameter("acceptPersonCode", String.class);
        if (ObjectUtil.isNull(org)){
            org = orgApplication.loadMainOrgByLoginName(acceptPersonCode);
        }
        if (ObjectUtil.isNotNull(org)){
            Operator operator = operatorApplication.createOperatorByPersonMemberId(org.getId());
            ThreadLocalUtil.putOperator(operator);
        }
        //设置默认值，并保存
        sapPurchase.setBsart("ZNE2");
        sapPurchase.setKnttp("K");
        sapPurchase.setPrototypeCode(sapPurchaseItemDto.getPrototypeCode());
        sapPurchase.setKostl(sapPurchaseItemDto.getKostl());
        String id = mannualStartWorkApplication.startWorkflow(sapPurchase,PROCESS_DEFINITION_KEY,"sapPurchase");
        SDO sdo = (SDO)ThreadLocalUtil.getVariable("sdo");
        String billCode = sdo.getString("billCode");
        sapPurchase.setBillCode(billCode);
        //转换明细，保存
        SapPurchaseItem sapPurchaseItem = new SapPurchaseItem();
        BeanUtil.copyProperties(sapPurchaseItemDto,sapPurchaseItem);
        sapPurchaseItem.setErnam(sapPurchaseItem.getAfnam());
        sapPurchaseItem.setBadat(new Date());
        sapPurchaseItem.setAfnam(org.getName());
        sapPurchaseItem.setAfnamId(org.getId());

        List<SapPurchaseItem> itemList = new ArrayList<>();
        itemList.add(sapPurchaseItem);
        this.sapPurchaseItemApplication.saveSapPurchaseItems(id,itemList);
        return sapPurchase;
    }


}
