package com.huigou.topsun.ep.change.application.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huigou.cache.DictUtil;
import com.huigou.cache.SystemCache;
import com.huigou.data.domain.model.CommonDomainConstants;
import com.huigou.data.domain.query.QueryPageRequest;
import com.huigou.data.query.model.QueryDescriptor;
import com.huigou.data.query.model.QueryModel;
import com.huigou.topsun.ep.change.application.EpChangeFormApplication;
import com.huigou.topsun.ep.change.application.EpChangeFormImplItemApplication;
import com.huigou.topsun.ep.change.application.EpChangeFormStockItemApplication;
import com.huigou.topsun.ep.change.domain.EpChangeForm;
import com.huigou.topsun.ep.change.domain.EpChangeFormImplItem;
import com.huigou.topsun.ep.change.domain.EpChangeFormStockItem;
import com.huigou.topsun.ep.change.domain.query.EpChangeFormQueryRequest;
import com.huigou.topsun.ep.change.repository.EpChangeFormImplItemRepository;
import com.huigou.topsun.ep.change.repository.EpChangeFormRepository;
import com.huigou.topsun.ep.change.repository.EpChangeFormStockItemRepository;
import com.huigou.topsun.sap.common.HttpClient;
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.opm.domain.model.org.Org;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.uasp.bpm.engine.domain.model.ProcUnitHandler;
import com.huigou.uasp.bpm.engine.domain.model.TaskExtension;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import sun.misc.BASE64Encoder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Auther: xin.lu
 * @Date: 2024/06/19/10:06
 * @Description:
 */
@Service("epChangeFormApplication")
public class EpChangeFormApplicationImpl extends FlowBroker implements EpChangeFormApplication {
    private final static Logger LOG = LoggerFactory.getLogger(EpChangeFormApplicationImpl.class);
    @Autowired
    private EpChangeFormRepository epChangeFormRepository;
    @Autowired
    private EpChangeFormStockItemApplication changeFormStockItemApplication;
    @Autowired
    private EpChangeFormImplItemApplication changeFormImplItemApplication;
    @Autowired
    private HttpClient httpClient;
    @Autowired
    SapMutualEpLogApplication sapMutualEpLogApplication;
    @Autowired
    private EpChangeFormImplItemRepository epChangeFormImplItemRepository;
    @Autowired
    private EpChangeFormStockItemRepository epChangeFormStockItemRepository;
    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        EpChangeForm epChangeForm = getBizEntity(EpChangeForm.class);
        if (epChangeForm.isNew()) {
            epChangeForm.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            epChangeForm = (EpChangeForm) commonDomainService.loadAndFillinProperties(epChangeForm);
        }
        epChangeForm = epChangeFormRepository.save(epChangeForm);
        List<EpChangeFormStockItem> changeFormStockItems = getBizEntities(EpChangeFormStockItem.class, "epChangeFormStockItem");
        changeFormStockItemApplication.saveEpChangeFormStockItems(epChangeForm.getId(),changeFormStockItems);

        List<EpChangeFormImplItem> changeFormImplItems = getBizEntities(EpChangeFormImplItem.class, "EpChangeFormImplItem");
        changeFormImplItemApplication.saveEpChangeFormImplItems(epChangeForm.getId(),changeFormImplItems);
        return epChangeForm.getId();
    }

    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(epChangeFormRepository.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 subProcUnitName = procUnitHandler.getSubProcUnitName();
            //查询到审批人组织信息
            String fullId = delegateTask.getAssignee();
            Org org = orgApplication.loadOrgByFullId(fullId);
            if (ObjectUtil.isNotNull(org)){
                if ("执行人".equals(subProcUnitName)){
                    //匹配部门执行人审批完，更新确认状态是时间
                    List<EpChangeFormImplItem> formImplItemList = epChangeFormImplItemRepository.findByEpChangeFormId(bizId);
                    for (EpChangeFormImplItem epChangeFormImplItem : formImplItemList) {
                        if (org.getId().equals(epChangeFormImplItem.getExecutorId())){
                            epChangeFormImplItem.setConfirm("1");
                            epChangeFormImplItem.setDate(new Date());
                            epChangeFormImplItem.setComments(procUnitHandler.getOpinion());
                        }
                    }
                    changeFormImplItemApplication.saveEpChangeFormImplItems(bizId,formImplItemList);

                    //匹配仓库环节审批完，更新确认状态是时间
                    List<EpChangeFormStockItem> stockItemList = epChangeFormStockItemRepository.findByEpChangeFormId(bizId);
                    for (EpChangeFormStockItem epChangeFormStockItem : stockItemList) {
                        if (org.getId().equals(epChangeFormStockItem.getExecutorId())){
                            epChangeFormStockItem.setConfirm("1");
                            epChangeFormStockItem.setDate(new Date());
                            epChangeFormStockItem.setComments(procUnitHandler.getOpinion());
                        }
                    }
                    changeFormStockItemApplication.saveEpChangeFormStockItems(bizId,stockItemList);
                }
            }
        }
    }

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

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        //super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        EpChangeForm epChangeForm = epChangeFormRepository.findOne(bizId);
        epChangeForm.setStatusId(status.getId());
        epChangeFormRepository.save(epChangeForm);
        this.feedBackSaleEcn(epChangeForm);
    }

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

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

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

    /**
     * 获取任务标题
     *
     * @param bizId
     * @return
     */
    private String getApprovalSubjectName(String bizId) {
        EpChangeForm epChangeForm = this.epChangeFormRepository.findOne(bizId);
        //查询 单据日期
        String fillinDateStr = DateUtil.getDateFormat("yyyy-MM-dd HH:mm:ss", epChangeForm.getFillinDate());
        //设置标题
        return String.format("%s-%s(%s)", "宝绅内部变更申请/通知单", epChangeForm.getBillCode(), fillinDateStr);
    }

    @Override
    public EpChangeForm findEpChangeFormById(String id) {
        return epChangeFormRepository.findOne(id);
    }

    @Override
    public EpChangeForm saveEpChangeForm(EpChangeForm epChangeForm) {
        return epChangeFormRepository.save(epChangeForm);
    }

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

    @Override
    public List<Map<String, Object>> queryApprovalPersons(String bizId) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "queryApprovalPersons");
        return this.sqlExecutorDao.queryToListMap(queryDescriptor.getSql(),bizId);
    }

    @Override
    public Map<String, Object> print(EpChangeFormQueryRequest queryRequest) {
        Map<String, Object> objectMap = this.slicedEpChangeFormList(queryRequest);
        List<Map<String, Object>> objectMaps = (List<Map<String, Object>>) objectMap.get("Rows");
        Map<String,Object> map = objectMaps.get(0);
        map.put("deptName",map.get("deptName")+"-"+map.get("personMemberName"));
        //处理产成品变更类型和原材料变更类型
        //例如：√ BRAND CHANGE 客户变更    BSN PROCESS CHANGE 内部工艺变更    PRODUCT MATERIAL CHANGE 产品材质变更
        // TEMPLATE CHANGE 版具变更    MATERIAL CHANGE 原材料变更    OTHERS 其它
        String reasonForChange = "";
        Map<String, String> reasonForChangeMap = new HashMap<>();
        String reasonForChangePD = (String) map.get("reasonForChange");
        String reasonForChangeMaterial = (String) map.get("materialReasonForChange");
        String printPage = "";
        //成品变更
        if (StringUtil.isNotBlank(reasonForChangePD)){
            reasonForChange = reasonForChangePD;
            reasonForChangeMap = DictUtil.getDictionary("reasonForChange");
            String[] split = reasonForChange.split(",");
            List<String> strings = Arrays.asList(split);
            StringBuilder change = new StringBuilder();
            Map<String, String> finalReasonForChangeMap = reasonForChangeMap;
            finalReasonForChangeMap.keySet().stream().limit(3).forEach(key->{
                if (strings.contains(key)){
                    change.append(" √ ");
                }
                if (StringUtil.isNotBlank(reasonForChangeMaterial)){
                    change.append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
                if (StringUtil.isNotBlank(reasonForChangePD)){
                    change.append(key).append(" ").append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
            });
            map.put("reasonForChange",change.toString());

            StringBuilder change2 = new StringBuilder();
            finalReasonForChangeMap.keySet().stream().skip(0).skip(1).skip(2).forEach(key->{
                if (strings.contains(key)){
                    change2.append(" √ ");
                }
                if (StringUtil.isNotBlank(reasonForChangeMaterial)){
                    change2.append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
                if (StringUtil.isNotBlank(reasonForChangePD)){
                    change2.append(key).append(" ").append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
            });
            map.put("reasonForChange2",change2.toString());
            printPage = "/print/topsun/epChangeForm.ftl";
        }
        //原材料变更
        if (StringUtil.isNotBlank(reasonForChangeMaterial)){
            reasonForChange = reasonForChangeMaterial;
            reasonForChangeMap = DictUtil.getDictionary("materialReasonForChange");
            String[] split = reasonForChange.split(",");
            List<String> strings = Arrays.asList(split);
            StringBuilder change = new StringBuilder();
            Map<String, String> finalReasonForChangeMap = reasonForChangeMap;
            finalReasonForChangeMap.keySet().stream().forEach(key->{
                if (strings.contains(key)){
                    change.append(" √ ");
                }
                if (StringUtil.isNotBlank(reasonForChangeMaterial)){
                    change.append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
                if (StringUtil.isNotBlank(reasonForChangePD)){
                    change.append(key).append(" ").append(finalReasonForChangeMap.get(key)).append("nbsp");
                }
            });
            map.put("reasonForChange",change.toString());
            printPage = "/print/topsun/epChangeMaterialForm.ftl";
        }
        map.put("printPage",printPage);
        //处理生效日期类型
        //例如：√ IMMEDIATE 立即变更    RUNNING CHANGE 正常变更（用完后变更）    SEASON 换季更改
        Map<String, String> changeEffective = DictUtil.getDictionary("changeEffective");
        StringBuilder effective = new StringBuilder();
        String[] splitE = map.get("changeEffective").toString().split(",");
        List<String> stringList = Arrays.asList(splitE);
        changeEffective.keySet().forEach(key->{
            if (stringList.contains(key)){
                effective.append("  √  ");
            }
            effective.append(key).append(" ").append(changeEffective.get(key)).append("nbsp");
        });
        map.put("changeEffective",effective.toString());

        File file = new File(SystemCache.getRealPath() +"/images/bsnLogo.png");
        try {
            FileInputStream inputFile = new FileInputStream(file);
            byte[] buffer = new byte[inputFile.available()];
            inputFile.read(buffer);
            inputFile.close();
            BASE64Encoder base64Encoder = new BASE64Encoder();
            String encode = base64Encoder.encode(buffer);
            map.put("bsnPng",encode);
        }catch (Exception e) {
            LOG.error("异常信息:" + e.getMessage());
        }
        // 获取Grid数据
        QueryPageRequest pageModel = queryRequest.getPageModel();
        pageModel.setPageSize(20);
        queryRequest.setPageModel(pageModel);
        queryRequest.setEpChangeFormId(queryRequest.getId());
        //查询Implementation 执行人（版具/模具等）
        Map<String, Object> implItemMap = changeFormImplItemApplication.findByEpChangeFormId(queryRequest);
        //查询Stock / Inventory 库存
        Map<String, Object> stockItemMap = changeFormStockItemApplication.findByEpChangeFormId(queryRequest);
        //查询审批人
        List<Map<String, Object>> mapList = this.queryApprovalPersons(queryRequest.getId());
        List<Map<String, Object>> implItemMaps = (List<Map<String, Object>>) implItemMap.get("Rows");
        implItemMaps.forEach(itemMap->{
            mapList.forEach(approvalMap -> {
                if (approvalMap.get("handlerName").equals(itemMap.get("executor"))){
                    itemMap.put("comment",approvalMap.get("opinion"));
                }
            });
            if (itemMap.get("date") != null && itemMap.get("date") != ""){
                itemMap.put("date",DateUtil.getDateFormat((Date) itemMap.get("date"),"yyyy-MM-dd"));
            }
        });
        List<Map<String, Object>> stockItemMaps = (List<Map<String, Object>>) stockItemMap.get("Rows");
        stockItemMaps.forEach(itemMap->{
            mapList.forEach(approvalMap -> {
                if (approvalMap.get("handlerName").equals(itemMap.get("executor"))){
                    itemMap.put("comment",approvalMap.get("opinion"));
                }
            });
            if (itemMap.get("date") != null && itemMap.get("date") != ""){
                itemMap.put("date",DateUtil.getDateFormat((Date) itemMap.get("date"),"yyyy-MM-dd"));
            }
        });
        map.put("printTime", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(LocalDateTime.now()));
        map.put("implItemMaps", implItemMaps);
        map.put("stockItemMaps", stockItemMaps);
        map.put("approvals", mapList);
        return map;
    }

    public void feedBackSaleEcn(EpChangeForm epChangeForm){
        Map<String,Object> map = new HashMap<>();
        //日志记录
        Map<String, Object> resultMap = new HashMap<>();
        //成品变更
        //String url = "pro/productionSolution/openEcn?pds="+epChangeForm.getPd();
        String url = "pro/productionSolution/openEcn?pds=";
        //原材料变更
        if (StringUtil.isNotBlank(epChangeForm.getMaterialReasonForChange())){
            url = url +epChangeForm.getPd()+"&type=material";
        }else {
            List<String> pds = new ArrayList<>();
            String pd = epChangeForm.getPd();
            String[] split = pd.split(",");
            //获取每个组合编码
            for (String s : split) {
                String[] split1 = s.split("/");
                List<String> list = Arrays.asList(split1);
                String s1 = list.get(0);//EP物料编码
                pds.add(s1);
            }
            String join = String.join(",", pds);
            url =url + join +"&type=product";
        }
        try {
            String execute = httpClient.executeForEp(map, url);
            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());
            }
            epChangeForm.setCode(epResult.getCode());
            epChangeForm.setMsg(epResult.getMsg());
            epChangeFormRepository.save(epChangeForm);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            resultMap.put("businessType", "ECN");
            resultMap.put("businessId", epChangeForm.getBillCode());
            resultMap.put("parameter", JSON.toJSONString(map));
            resultMap.put("sequence", resultMap.get("row"));
            sapMutualEpLogApplication.saveSapMutualEpLog(resultMap);
        }
    }
}
