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


import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huigou.cache.DictUtil;
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.task.BaseTask;
import com.huigou.topsun.sap.common.DefaultHttpClient;
import com.huigou.topsun.sap.common.domain.SapResult;
import com.huigou.topsun.sap.costReimbursement.application.SapCostReimbursementApplication;
import com.huigou.topsun.sap.costReimbursement.domain.SapCostReimbursement;
import com.huigou.topsun.sap.costReimbursement.domain.SapCostReimbursementDetail;
import com.huigou.topsun.sap.costReimbursement.domain.query.SapCostReimbursementQueryRequest;
import com.huigou.topsun.sap.costReimbursement.domain.vo.PaymentReceiptVo;
import com.huigou.topsun.sap.costReimbursement.repostiory.SapCostReimbursementDetailRepository;
import com.huigou.topsun.sap.costReimbursement.repostiory.SapCostReimbursementRepository;
import com.huigou.topsun.util.MyBaseUtil;
import com.huigou.uasp.bmp.common.BizBillStatus;
import com.huigou.uasp.bmp.operator.OperatorApplication;
import com.huigou.uasp.bpm.ApprovalParameter;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.uasp.bpm.engine.application.WorkflowApplication;
import com.huigou.uasp.bpm.engine.domain.model.ProcUnitHandler;
import com.huigou.uasp.bpm.engine.domain.model.TaskExtension;
import com.huigou.util.*;
import lombok.SneakyThrows;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;


import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@Service("sapCostReimbursementApplication")
public class SapCostReimbursementApplicationImpl extends FlowBroker implements SapCostReimbursementApplication {

    private final static Logger LOG = LoggerFactory.getLogger(SapCostReimbursementApplicationImpl.class);
    @Autowired
    private SapCostReimbursementDetailRepository costReimbursementDetailRepository;
    @Autowired
    private SapCostReimbursementRepository costReimbursementRepository;
    @Resource
    private OperatorApplication operatorApplication;

    @Autowired
    DefaultHttpClient defaultHttpClient;
    @Autowired
    private WorkflowApplication workflowApplication;
    @Autowired
    BaseTask baseTask;


    @SneakyThrows
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        SDO sdo = this.getBizAndApprovalData();
        SapCostReimbursement sapCostReimbursement = getBizEntity(SapCostReimbursement.class);
        if (sapCostReimbursement.isNew()) {
            sapCostReimbursement.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            sapCostReimbursement = (SapCostReimbursement) commonDomainService.loadAndFillinProperties(sapCostReimbursement);
        }
        sapCostReimbursement = costReimbursementRepository.save(sapCostReimbursement);

        List<SapCostReimbursementDetail> CRDetailAll = getBizEntities(SapCostReimbursementDetail.class, "CRDetail");
        if (CRDetailAll.size() > 0) {
            List<String> nos = new ArrayList<>();
            for (SapCostReimbursementDetail item : CRDetailAll) {
                item.setReimbursementBaseInfoId(sapCostReimbursement.getId());
                if (StringUtil.isBlank(item.getZpayStaus())){
                    item.setZpayStaus("未支付");
                }
                if (nos.contains(item.getZepItemno())){
                    LOG.info("明细行数据：{}", JSON.toJSONString(CRDetailAll));
                    throw new RuntimeException("明细行项目编号重复");
                }
                nos.add(item.getZepItemno());
                costReimbursementDetailRepository.save(item);
            }
        }
        return sapCostReimbursement.getId();
    }

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

    /**
     * 获取任务标题
     *
     * @param sapCostReimbursement
     * @return
     */
    private String getApprovalSubjectName(SapCostReimbursement sapCostReimbursement ) {
        String fillinDateStr = DateUtil.getDateFormat(sapCostReimbursement.getFillinDate());
        String typeName = sapCostReimbursement.getZepFtypename();
        return String.format("%s-%s-%s(%s)",sapCostReimbursement.getPersonMemberName(),typeName , sapCostReimbursement.getBillCode(),fillinDateStr);
    }

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(costReimbursementRepository.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);
        if (this.isApprovalProcUnit(delegateTask) && this.getApprovalParameter().isAdvanceProcessAction()) {
            TaskExtension te = actApplication.loadRuntimeTaskExtension(delegateTask.getId());
            cn.hutool.core.lang.Assert.notNull(te, String.format("未查询到流程任务【%s】的扩展信息", delegateTask.getId()));
            // 获取流程任务对应的审批环节信息
            ProcUnitHandler procUnitHandler = procUnitHandlerApplication.loadProcUnitHandler(te.getProcUnitHandlerId());
            String subProcUnitId = procUnitHandler.getSubProcUnitId();
            if ("fundNode".equals(subProcUnitId) || "applyPerson".equals(subProcUnitId)) {
                //在资产节点传到SAP
                this.sendSapDate(this.costReimbursementRepository.findOne(bizId));
            }
        }
    }

    /**
     * 回收事件
     **/
    @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(SapCostReimbursement.class, bizId, status.getId());
    }
    /**
     * 流程实例结束
     *
     * @param delegateExecution
     */
    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        //super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        SapCostReimbursement sapCostReimbursement = costReimbursementRepository.findOne(bizId);
        sapCostReimbursement.setStatusId(status.getId());
        costReimbursementRepository.save(sapCostReimbursement);
        //审核完成、远程调用sap接口
        //sendSapDate(sapCostReimbursement);
    }

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

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

    @Override
    public SapCostReimbursement loadSapCostReimbursementById(String id) {
        return costReimbursementRepository.findOne(id);
    }

    @Override
    public Map<String, Object> slicedSapCostReimbursementQuery(SapCostReimbursementQueryRequest query) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "slicedSapCostReimbursementQuery");
        QueryModel model = this.sqlExecutorDao.getQueryModel(queryDescriptor, query);
        model.putDictionary("status", DictUtil.getDictionary("bizBillStatus"));
        model.addCriteria(" order by bill_code desc ");
       // return this.sqlExecutorDao.executeSlicedQuery(queryDescriptor, query);
        return this.sqlExecutorDao.executeSlicedQuery(model);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void deleteSapCostReimbursementById(String id) {
        SapCostReimbursement costReimbursement = costReimbursementRepository.findOne(id);
        List<SapCostReimbursementDetail> all = costReimbursementDetailRepository.findAllByReimbursementBaseInfoId(id);
        costReimbursementDetailRepository.delete(all);
        costReimbursementRepository.delete(costReimbursement);
    }

    @Override
    @Transactional
    public void deleteSapCostReimbursementByIds(List<String> ids) {
        ids.forEach(this::deleteSapCostReimbursementById);
    }

    /**
     * 远程调用sap接口，传递数据
     */
    public void sendSapDate(SapCostReimbursement sapCostReimbursement) {
        if (sapCostReimbursement.getStatusId() == BizBillStatus.APPLYING.getId()) {
            throw new RuntimeException("本数据未经审批完成！");
        }
        ObjectMapper objectMapper = new ObjectMapper();

        List<SapCostReimbursementDetail> all = costReimbursementDetailRepository.findAllByReimbursementBaseInfoId(sapCostReimbursement.getId());
        List<Object> paramList = new ArrayList<>();
        List<Map<String, Object>> itemList = new ArrayList<>();
        Map<String, Object> paramMap = new HashMap<>();
        new ArrayList<>();

        Map<String, Object> map = MyBaseUtil.convertToMap(sapCostReimbursement, true);
        map.remove("ZEP_FTYPE");
        map.remove("ZEP_NO");
        map.remove("PARTNER");
        map.remove("BANKN");
        map.remove("KOINH");
        map.remove("BANKL");
        map.remove("SWIFT");
        if (sapCostReimbursement.getZepFcrdate() != null){
            String dateFormat = DateUtil.getDateFormat(sapCostReimbursement.getZepFcrdate(), "yyyyMMdd");
            map.put("ZEP_FCRDATE",dateFormat);
        }

        // 封装参数
        for (SapCostReimbursementDetail costReimbursementDetail : all) {

            Map<String, Object> detailMap = MyBaseUtil.convertToMap(costReimbursementDetail, true);
            //已付款，传S
            String zpayStaus = (String) detailMap.get("ZPAY_STAUS");
            if ("已支付".equals(zpayStaus)){
                detailMap.put("ZPAY_STAUS","S");
            }else {
                detailMap.put("ZPAY_STAUS","");
            }
            String budat = DateUtil.getDateFormat(new Date(), "yyyyMMdd");
            detailMap.put("BUDAT",budat);
            detailMap.put("BLDAT",budat);
            costReimbursementDetail.setBudat(new Date());
            costReimbursementDetail.setBldat(new Date());
            if (costReimbursementDetail.getZepFpldate() != null){
                String dateFormat = DateUtil.getDateFormat(costReimbursementDetail.getZepFpldate(), "yyyyMMdd");
                detailMap.put("ZEP_FPLDATE",dateFormat);
            }
            //对账单号
            detailMap.put("ZYL04",costReimbursementDetail.getXblnr());

            //ZYL05按照规则传0，但实体发票号这个字段就不用传“空”这个字符给我了，直接就不传值
            if ("0".equals(costReimbursementDetail.getZyl05())){
                detailMap.put("ZYL06","");
            }
            detailMap.putAll(map);
            itemList.add(detailMap);
            costReimbursementDetail.setBankn1(sapCostReimbursement.getBankn1());
            costReimbursementDetail.setZepTxt1(sapCostReimbursement.getZepTxt1());
            costReimbursementDetail.setZt012kText1(sapCostReimbursement.getZt012kText1());
            costReimbursementDetailRepository.save(costReimbursementDetail);
        }
        paramMap.put("ITEM", itemList);
        paramMap.put("MANDT", "300");
        paramMap.put("ZEP_FTYPE", sapCostReimbursement.getZepFtype());
        paramMap.put("ZEP_NO", sapCostReimbursement.getBillCode());
        paramList.add(paramMap);

        String url = "cud_fi012/cud_fi012";
        try {
            String result = defaultHttpClient.execute(paramList, url);
            List<SapResult> resultList = JSONObject.parseArray(result, SapResult.class);

            for (SapResult sapResult : resultList) {
                if ("S".equals(sapResult.getTYPE())) {
                    for (SapCostReimbursementDetail reimbursementDetail : all) {
                        if (sapResult.getMESSAGE_V2().equals(reimbursementDetail.getZepItemno())){
                            reimbursementDetail.setBelnr(sapResult.getMESSAGE_V3());
                            reimbursementDetail.setGjahr(sapResult.getMESSAGE_V4());
                            reimbursementDetail.setMsgty(sapResult.getTYPE());
                            reimbursementDetail.setMsgtx(sapResult.getMESSAGE());
                            costReimbursementDetailRepository.save(reimbursementDetail);
                        }
                    }
                }else {
                    throw new RuntimeException("数据传输失败，请稍后手动重试！" + sapResult.getMESSAGE());
                }
            }
        } catch (IOException e) {
            LOG.error("sap服务器无响应请稍后手动重试！error: {}", e.getMessage());
            throw new RuntimeException("sap服务器无响应请稍后手动重试！error:" + e.getMessage());
        }
    }

    @Override
    public void savePaymentReceiptVo(PaymentReceiptVo paymentReceiptVo) {
        SapCostReimbursement reimbursement = costReimbursementRepository.findByBillCode(paymentReceiptVo.getBillCode());
        if (ObjectUtil.isNull(reimbursement)){
            throw new RuntimeException("未找到单据编号为：" + paymentReceiptVo.getBillCode() + " 的数据");
        }
        List<SapCostReimbursementDetail> detailList = costReimbursementDetailRepository.findAllByReimbursementBaseInfoId(reimbursement.getId());
        for (SapCostReimbursementDetail sapCostReimbursementDetail : detailList) {
            sapCostReimbursementDetail.setBelnr1(paymentReceiptVo.getBelnr1());
            sapCostReimbursementDetail.setGjahr1(paymentReceiptVo.getGjahr1());
            if ("X".equals(paymentReceiptVo.getZflag())){
                sapCostReimbursementDetail.setZpayStaus("已冲销");
            }else {
                sapCostReimbursementDetail.setZpayStaus("已支付");
            }
            costReimbursementDetailRepository.save(sapCostReimbursementDetail);
        }
        reimbursement.setFinishedDate(new Date());
        costReimbursementRepository.save(reimbursement);
        //
        //this.endTask(reimbursement);
        //在接收到SAP回执消息后，修改任务标题和当前时间，让申请人能看到该任务
        //this.updateActRuTaskExtension(reimbursement.getId());
        this.makeACopyFor(reimbursement);
    }

    @Override
    public void endTask(SapCostReimbursement reimbursement) {
        Operator operator = operatorApplication.createOperatorByPersonMemberId(reimbursement.getPersonMemberId());
        ThreadLocalUtil.putOperator(operator);
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "queryTaskByBusinessKey");
        ApprovalParameter approvalParameter = this.sqlExecutorDao.queryToObject(queryDescriptor.getSql(), ApprovalParameter.class, reimbursement.getId());
        approvalParameter.setProcessAction("advance");
        approvalParameter.setHandleResult(1);
        approvalParameter.setHandleOpinion("同意！");
        Map<String, Object> variables = new HashMap();
        SDO localSdo = new SDO();
        localSdo.putProperty("processAction", "advance");
        ThreadLocalUtil.putVariable("sdo",localSdo);
        ThreadLocalUtil.putVariable("_approvalParameter_",approvalParameter);
        this.workflowApplication.advance(approvalParameter.getTaskId(),variables);
    }

    @Override
    public Integer checkzyl06(String zyl06) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "checkzyl06");
        String sql = queryDescriptor.getSql();
        int i = this.sqlExecutorDao.queryToInt(sql, zyl06);
        return i;
    }

    @Override
    public Map<String, Object> queryKostlByPersonCode(String personCode) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "queryKostlByPersonCode");
        String sql = queryDescriptor.getSql();
        return this.sqlExecutorDao.queryToMap(sql, personCode);
    }

    @Override
    public Map<String, Object> slicedAdvancePaymentList(SapCostReimbursementQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "slicedAdvancePaymentList");
        QueryModel model = this.sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest);
        model.putDictionary("status", DictUtil.getDictionary("bizBillStatus"));
        return this.sqlExecutorDao.executeSlicedQuery(model);
    }

    @Override
    public List<String> excludeCompletePartnerInvs(String partner) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "excludeCompletePartnerInvs");
        String sql = queryDescriptor.getSql();
        return this.sqlExecutorDao.queryToList(sql,String.class, partner);
    }

    public void makeACopyFor(SapCostReimbursement reimbursement) {
        // 流程结束给申请人发送抄送
        List<String> executorIds = new ArrayList<>(1);
        executorIds.add(reimbursement.getPersonMemberId());
        String taskId = this.baseTask.queryTaskByBizId(reimbursement.getId());
        Operator operator = operatorApplication.createOperatorByPersonMemberId(reimbursement.getPersonMemberId());
        ThreadLocalUtil.putOperator(operator);
        this.workflowService.makeACopyFor(taskId, executorIds,"SAP付款回执："+reimbursement.getZepFtypename()+"-"+reimbursement.getBillCode());
    }

    public void updateActRuTaskExtension(String bizId){
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "updateActRuTaskExtension");
        String sql = queryDescriptor.getSql();
        this.sqlExecutorDao.executeUpdate(sql, "付款完成、sap回执：",new Date(),bizId);
    }

    public static void main(String[] args) throws JsonProcessingException {
//        post.setHeader("Content-type", "application/json;charset=utf-8");

        String usernameAndPassword = "rest_user:Bsn123456";
        System.out.println("Authorization");
        System.out.println("Basic " + Base64.getEncoder().encodeToString(usernameAndPassword.getBytes()));
    }

}