package com.yem.wm.utils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.ISimpleProperty;
import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicLocaleProperty;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.entity.operate.result.IOperateInfo;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.entity.property.BillTypeProp;
import kd.bos.entity.property.EntryProp;
import kd.bos.entity.property.MulBasedataProp;
import kd.bos.exception.KDBizException;
import kd.bos.orm.ORM;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.bos.servicehelper.user.UserServiceHelper;

/** 版本变更帮助类
 * @author 夜子
 * @ClassName NewVersionHelper
 * @description: 版本变更帮助类
 * @date 2023年07月06日
 * @version: 1.0
 */
public class NewVersionHelper {
	public static final String KEY_REL = "yem_tpl_versionsrel";//【版本变更关联追踪表】单据标识-扩展开发库
	public static final String KEY_TPL = "yem_tpl_versionsetting";//【创建新版本方案维护】单据标识
	public static final String KEY_LIST = "yem_tpl_versionresume";//【变更履历】单据标识
	public static final Map<String, String> KEY_TPL_MAP = new HashMap<>();
	static {
		KEY_TPL_MAP.put(null, "yem_tpl_versionsrel");
		KEY_TPL_MAP.put("secd", "yem_tpl_versionsrel");
		KEY_TPL_MAP.put("scm", "yem_tpl_versionsrel_scm");
	}
	private boolean isRequired = false;
	private boolean isChanged = false;
	private DynamicObject tplObj;
	private String requireKey;
	private String changeKey;
	
	public boolean isRequired() {
		return isRequired;
	}

	public boolean isChanged() {
		return isChanged;
	}

	public DynamicObject getTplObj() {
		return tplObj;
	}
	
	public String getRequireKey() {
		return requireKey;
	}

	public String getChangeKey() {
		return changeKey;
	}

	public NewVersionHelper(String entityNumber){
		tplObj = queryTemplate(entityNumber);
		if(tplObj != null) {
			requireKey = tplObj.getString("yem_requirebill.number");
			changeKey = tplObj.getString("yem_changebill.number");
			if(entityNumber.equals(changeKey)) {
				isChanged = true;
			}else {
				isRequired = true;
			}
		}
	}
	
	/**
	 * 查询版本变更方案
	 */
	public static DynamicObject queryTemplate(String entityNumber) {
		QFilter qFilter = new QFilter("enable", QCP.equals, "1");
//		qFilter.and(new QFilter("status", QCP.equals, "C"));
		qFilter.and(new QFilter("yem_requirebill.number", QCP.equals, entityNumber).or(new QFilter("yem_changebill.number", QCP.equals, entityNumber)));
		String selectFields = DynamicObjectUtil.getSelectfields(KEY_TPL, false);
		selectFields = DynamicObjectUtil.getEntrySelectfields(selectFields, KEY_TPL, "yem_colsmap", false);
		selectFields = DynamicObjectUtil.getEntrySelectfields(selectFields, KEY_TPL, "yem_checkmap", false);
		selectFields = DynamicObjectUtil.getEntrySelectfields(selectFields, KEY_TPL, "yem_checkdelrow", false);
		selectFields = DynamicObjectUtil.getEntrySelectfields(selectFields, KEY_TPL, "yem_billtypes", false);
		return BusinessDataServiceHelper.loadSingleFromCache(KEY_TPL, selectFields, new QFilter[] { qFilter });
	}
	
	/**
	 * 构建返回持久化的变更单实体
	 */
	public static DynamicObject newVersion(String entityNumber, Object fromPkId) {
		return newVersion(queryTemplate(entityNumber), fromPkId);
	}
	
	/**
	 * 构建返回持久化的变更单实体
	 */
	public static DynamicObject newVersion(DynamicObject tplObj, Object fromPkId) {
		noSettings(tplObj);
		String fromKey = tplObj.getString("yem_requirebill.number");
		String toKey = tplObj.getString("yem_changebill.number");
		DynamicObject oldDataEntity = BusinessDataServiceHelper.loadSingle(fromPkId, fromKey);
		DynamicObject newDataEntity = BusinessDataServiceHelper.newDynamicObject(toKey);
		DynamicObjectUtil.copyDynamicObject(oldDataEntity, newDataEntity, 2, false, true, true);
		newDataEntity.set("billstatus", "A");
		newDataEntity.set("yem_masterid", fromPkId);
		int vno = oldDataEntity.getInt("yem_version") + 1;
		newDataEntity.set("yem_version", vno);
		newDataEntity.set("yem_effective", false);
		newDataEntity.set("billno", oldDataEntity.getString("billno").concat("_V").concat(String.valueOf(vno)));
		newDataEntity.set("yem_changeman", UserServiceHelper.getCurrentUser("name"));
		newDataEntity.set("yem_changedate", new Date());
		newDataEntity.set("yem_effector", null);
		newDataEntity.set("yem_effectdate", null);
		setBillTypes(newDataEntity, tplObj.getDynamicObjectCollection("yem_billtypes"), true);
//		SaveServiceHelper.save(new DynamicObject[] {newDataEntity});


		OperationResult result = SaveServiceHelper.saveOperate(toKey, new DynamicObject[] {newDataEntity}, OperateOption.create());
		checkResult(result, "变更单保存失败。", newDataEntity);
		matchVersions(oldDataEntity, newDataEntity, tplObj.getPkValue());
		return newDataEntity;
	}

	/**
	 * 变更单生效
	 */
	public static void effectChange(String entityNumber, DynamicObject dataEntity) {
		effectChange(queryTemplate(entityNumber), dataEntity);
	}
	
	/**
	 * 变更单生效
	 */
	public static void effectChange(DynamicObject tplObj, DynamicObject dataEntity) {
		noSettings(tplObj);
		String entityNumber = dataEntity.getDynamicObjectType().getName();
		String yem_requirebill = tplObj.getString("yem_requirebill.number");
		String yem_changebill = tplObj.getString("yem_changebill.number");
		dataEntity = BusinessDataServiceHelper.loadSingle(dataEntity.getPkValue(), yem_changebill);
		int vno = dataEntity.getInt("yem_version");
		long masterid = dataEntity.getLong("yem_masterid");
		if(masterid > 0 && entityNumber.equals(yem_changebill)) {
			DynamicObject oldDataEntity = BusinessDataServiceHelper.loadSingle(masterid, yem_requirebill);
			if(vno == 2) {//第一次变更要生成版本为一的变更单记录初版单据内容
				DynamicObject newDataEntity = BusinessDataServiceHelper.newDynamicObject(yem_changebill);
				DynamicObjectUtil.copyDynamicObject(oldDataEntity, newDataEntity, 2, false, true, true);
				newDataEntity.set("yem_version", 1);
				newDataEntity.set("yem_masterid", masterid);
				newDataEntity.set("billno", oldDataEntity.getString("billno").concat("_V1"));
				newDataEntity.set("yem_effective", true);
				setBillTypes(newDataEntity, tplObj.getDynamicObjectCollection("yem_billtypes"), true);
				
//				SaveServiceHelper.save(new DynamicObject[] {newDataEntity});
				OperationResult result1 = SaveServiceHelper.saveOperate(yem_changebill, new DynamicObject[] {newDataEntity}, OperateOption.create());
				checkResult(result1, "一版本变更单保存失败。", newDataEntity);
				matchVersions(oldDataEntity, newDataEntity, tplObj.getPkValue());
			}
			//查询关联表数据
			String dbRouteKey = oldDataEntity.getDynamicObjectType().getDBRouteKey();
			QFilter qFilter = new QFilter("yem_tplid", QCP.equals, tplObj.getPkValue());
			qFilter.and(new QFilter("yem_masterid", QCP.equals, oldDataEntity.getPkValue()));
			qFilter.and(new QFilter("yem_xmasterid", QCP.equals, dataEntity.getPkValue()));
			String selectFields = DynamicObjectUtil.getSelectfields(KEY_TPL_MAP.get(dbRouteKey), false);
			DynamicObject[] rels = BusinessDataServiceHelper.load(KEY_TPL_MAP.get(dbRouteKey), selectFields, new QFilter[] { qFilter });
			//根据关联表反写变更数据到源单
			dataEntity.set("yem_effector", UserServiceHelper.getCurrentUser("name"));
			dataEntity.set("yem_effectdate", new Date());
			dataEntity.set("yem_effective", true);
			
			List<DynamicObject> relObjList = new ArrayList<>();
			copyChange2SrcByVersionRelData(oldDataEntity, dataEntity, dataEntity, oldDataEntity, rels, relObjList, tplObj.getPkValue());
			if(relObjList.size() > 0) {
				SaveServiceHelper.save(relObjList.toArray(new DynamicObject[0]));
			}
			setBillTypes(oldDataEntity, tplObj.getDynamicObjectCollection("yem_billtypes"), false);
			
//			SaveServiceHelper.save(new DynamicObject[] {dataEntity});
//			SaveServiceHelper.save(new DynamicObject[] {oldDataEntity});
			OperationResult result2 = SaveServiceHelper.saveOperate(yem_changebill, new DynamicObject[] {dataEntity}, OperateOption.create());
			checkResult(result2, "变更单生效保存失败。", dataEntity);
			OperationResult result3 = SaveServiceHelper.saveOperate(yem_requirebill, new DynamicObject[] {oldDataEntity}, OperateOption.create());
			checkResult(result3, "源单生效保存失败。", oldDataEntity);
		}
	}
	
	private static void noSettings(DynamicObject tplObj) {
		if(tplObj == null) {
			throw new KDBizException("未设置版本变更方案。");
		}
	}
	
	/**
	 * 检验单据生成结果，失败则提示并抛出异常
	 */
	public static void checkResult(OperationResult result, String errMsgTitle, DynamicObject dataEntity) {
		if(!result.isSuccess()) {
			StringBuilder buffer = new StringBuilder(errMsgTitle);
			buffer.append("\r\n").append("Message:").append(result.getMessage()).append("\r\n").append("Details:");
			List<IOperateInfo> allErrorOrValidateInfo = result.getAllErrorOrValidateInfo();
			for (IOperateInfo iOperateInfo : allErrorOrValidateInfo) {
				buffer.append("\r\n");
				String message = iOperateInfo.getMessage();
				if(message.contains("正在PC端编辑该记录") || message.contains("当前单据已在其他页签中打开")) {
					SaveServiceHelper.save(new DynamicObject[] {dataEntity});
					return;
				}
				buffer.append(message);
			}
			throw new KDBizException(buffer.toString());
		}
	}
	
	/**
	 * 变更单单据类型映射
	 */
	public static void setBillTypes(DynamicObject newDataEntity, DynamicObjectCollection yem_billtypes, boolean change) {
		String fromBilltype = change ? "yem_srcbilltype" : "yem_changebilltype";
		String toBilltype = change ? "yem_changebilltype" : "yem_srcbilltype";	
		DataEntityPropertyCollection properties = newDataEntity.getDynamicObjectType().getProperties();
		for(IDataEntityProperty property : properties) {
			String name = property.getName();
			//分录处理
			if(property instanceof EntryProp) {
				DynamicObjectCollection dyObjCollection = newDataEntity.getDynamicObjectCollection(name);
				for(DynamicObject row : dyObjCollection) {
					setBillTypes(row, yem_billtypes, change);
				}
			}//字段处理
			else if(property instanceof BillTypeProp){
				DynamicObject newBillType = null;
				String billTypeId = newDataEntity.getDynamicObject(name) == null ? "" : newDataEntity.getDynamicObject(name).getPkValue().toString();
				for (DynamicObject row : yem_billtypes) {
					DynamicObject yem_srcbilltype = row.getDynamicObject(fromBilltype);
					if(yem_srcbilltype != null && yem_srcbilltype.getString("id").equals(billTypeId)) {
						newBillType = row.getDynamicObject(toBilltype);
					}
				}
				newDataEntity.set(name, newBillType);
			}
		}
	}
	
	/**
	 * 构建原始单据和变更单据的关联关系
	 */
	private static void matchVersions(DynamicObject from, DynamicObject to, Object tplPkId) {
		List<DynamicObject> relObjList = new ArrayList<>();
		DynamicObjectType toType = to.getDynamicObjectType();
		DataEntityPropertyCollection toProperties = toType.getProperties();
		DynamicObjectType fromType = from.getDynamicObjectType();
		DataEntityPropertyCollection fromProperties = fromType.getProperties();
		//表头处理
		DynamicObject relObj = newVersionRelData(from, to, tplPkId, fromType.getName(), from.getPkValue(), to.getPkValue());
		relObjList.add(relObj);
		for(IDataEntityProperty toProperty : toProperties) {
			//分录处理
			if(toProperty instanceof EntryProp) {
				String name = toProperty.getName();
				if(!fromProperties.containsKey(name)) {
					continue;
				}
				DynamicObjectCollection toDynamicObjectCollection = to.getDynamicObjectCollection(name);
				DynamicObjectCollection fromDynamicObjectCollection = from.getDynamicObjectCollection(name);
				for(DynamicObject fromObj : fromDynamicObjectCollection) {
					if(fromObj.getPkValue() == null) {
						continue;
					}
					Object fromEntryPk = fromObj.getPkValue();//原始主键
					String fromEntrySeq = fromObj.getString("seq");//原始序号
					for(DynamicObject toObj : toDynamicObjectCollection) {
						if(toObj.getPkValue() == null) {
							continue;
						}
						Object toEntryPk = toObj.getPkValue();//变更主键
						String toEntrySeq = toObj.getString("seq");//原始序号
						if(fromEntrySeq.equals(toEntrySeq)) {
							DynamicObject relEntryObj = newVersionRelData(from, to, tplPkId, fromDynamicObjectCollection.getDynamicObjectType().getName(),
									fromEntryPk, toEntryPk);
							relObjList.add(relEntryObj);
							break;
						}
					}
				}
			}
		}
		SaveServiceHelper.save(relObjList.toArray(new DynamicObject[0]));
	}
	
	/**
	 * 构建【版本变更关联追踪表】数据
	 */
	private static DynamicObject newVersionRelData(DynamicObject from, DynamicObject to, Object tplPkId, String entitykey, Object fromEntryPk, Object toEntryPk) {
		DynamicObject relObj = null;
		String dbRouteKey = from.getDynamicObjectType().getDBRouteKey();
		if(KEY_TPL_MAP.containsKey(dbRouteKey)) {
			relObj = BusinessDataServiceHelper.newDynamicObject(KEY_TPL_MAP.get(dbRouteKey));
		}else {
			throw new KDBizException("当前模块分库未配置版本关联追踪表，请联系管理员。");
		}
		relObj.set("yem_tplid", tplPkId);//变更方案ID
		relObj.set("yem_masterid", from.getPkValue());//主数据内码
		relObj.set("yem_xmasterid", to.getPkValue());//变更单内码
		relObj.set("yem_vno", to.get("yem_version"));//版本号
		relObj.set("yem_entitykey", entitykey);//单据(体)标识
		relObj.set("yem_pkid", fromEntryPk);//原始主键
		relObj.set("yem_xpkid", toEntryPk);//变更单主键
		
		return relObj;
	}
	
	/**
	 * 根据关联表反写变更数据到源单
	 */
	private static void copyChange2SrcByVersionRelData(DynamicObject srcEntity, DynamicObject changeEntity, DynamicObject from, DynamicObject to, 
			 DynamicObject[] rels, List<DynamicObject> relObjList, Object tplPkId) {
		DynamicObjectType toType = to.getDynamicObjectType();
		DataEntityPropertyCollection toProperties = toType.getProperties();
		DynamicObjectType fromType = from.getDynamicObjectType();
		DataEntityPropertyCollection fromProperties = fromType.getProperties();
		
		for(IDataEntityProperty toProperty : toProperties) {
			String name = toProperty.getName();
			if(!fromProperties.containsKey(name)) {
				continue;
			}
			//分录处理
			if(toProperty instanceof EntryProp) {
				List<String> fromEntryPks = new ArrayList<>();
				List<String> toEntryPks = new ArrayList<>();
				DynamicObjectCollection toDynamicObjectCollection = to.getDynamicObjectCollection(name);
				DynamicObjectCollection fromDynamicObjectCollection = from.getDynamicObjectCollection(name);
				for (DynamicObject fromObj : fromDynamicObjectCollection) {
					String fromEntryPk = fromObj.getPkValue() == null ? "" : fromObj.getPkValue().toString();//变更分录ID
					DynamicObject dynamicObject = null;
					boolean isadd = false;//是追加的行
					if(fromEntryPk.length() > 0) {
						fromEntryPks.add(fromEntryPk);
						A:for (DynamicObject toObj : toDynamicObjectCollection) {
							String toEntryPk = toObj.getPkValue() == null ? "" : toObj.getPkValue().toString();//原始分录ID
							if(toEntryPk.length() > 0) {
								//关联处理
								for (DynamicObject rel : rels) {
									String yem_entitykey = rel.getString("yem_entitykey");//单据体标识
									String yem_pkid = rel.getString("yem_pkid");//原始主键
									String yem_xpkid = rel.getString("yem_xpkid");//变更单主键
									if(name.equals(yem_entitykey) && toEntryPk.equals(yem_pkid) && fromEntryPk.equals(yem_xpkid)) {
										dynamicObject = toObj;
										break A;
									}
								}
							}
						}
					}
					DynamicObjectType toObjType = toDynamicObjectCollection.getDynamicObjectType();
					if(dynamicObject == null) {
						dynamicObject = new DynamicObject(toObjType);
						isadd = true;
					}
					
					copyChange2SrcByVersionRelData(srcEntity, changeEntity, fromObj, dynamicObject, rels, relObjList, tplPkId);
					if(isadd) {
						long genLongId = ORM.create().genLongId(toObjType);
						toEntryPks.add(String.valueOf(genLongId));
						dynamicObject.set("id", genLongId);
						toDynamicObjectCollection.add(dynamicObject);
						DynamicObject relObj = newVersionRelData(srcEntity, changeEntity, tplPkId, toObjType.getName(), genLongId, fromObj.getPkValue());
						relObjList.add(relObj);
					}
				}
				//去掉删除的行
				for (DynamicObject rel : rels) {
					String yem_entitykey = rel.getString("yem_entitykey");//单据体标识
					String yem_pkid = rel.getString("yem_pkid");//原始主键
					String yem_xpkid = rel.getString("yem_xpkid");//变更单主键
					if(name.equals(yem_entitykey) && fromEntryPks.contains(yem_xpkid)) {
						toEntryPks.add(yem_pkid);
					}
				}
				for (int i = 0; i < toDynamicObjectCollection.size(); i++) {
					DynamicObject toObj = toDynamicObjectCollection.get(i);
					String toEntryPk = toObj.getPkValue() == null ? "0" : toObj.getPkValue().toString();
					if(!"0".equals(toEntryPk) && !toEntryPks.contains(toEntryPk)) {
						toDynamicObjectCollection.remove(i--);
					}
				}
			}//多选基础资料类处理
			else if(toProperty instanceof MulBasedataProp) {
				MulBasedataProp mulBasedataProp = ((MulBasedataProp) toProperty);
				
				IDataEntityType itemType = mulBasedataProp.getItemType();
				ISimpleProperty primaryKey = itemType.getPrimaryKey();
				DynamicObjectCollection toColls = (DynamicObjectCollection)to.get(name);
				toColls.clear();
				DynamicObjectType toDynamicObjectType = toColls.getDynamicObjectType();
				
				DynamicObjectCollection fromColls = (DynamicObjectCollection)from.get(name);
				for (DynamicObject coll : fromColls) {
					DynamicObject mulBaseData = new DynamicObject(toDynamicObjectType);
					copyChange2SrcByVersionRelData(srcEntity, changeEntity, coll, mulBaseData, rels, relObjList, tplPkId);
					primaryKey.resetValue(mulBaseData);
					toColls.add(mulBaseData);
				}
			}//多语言表处理
			else if(toProperty instanceof DynamicLocaleProperty) {
				DynamicLocaleProperty localeProperty = ((DynamicLocaleProperty) toProperty);
				
				IDataEntityType itemType = localeProperty.getItemType();
				ISimpleProperty primaryKey = itemType.getPrimaryKey();	
				DynamicObjectCollection toColls = (DynamicObjectCollection)to.get(name);
				toColls.clear();
				DynamicObjectType toDynamicObjectType = toColls.getDynamicObjectType();
				
				DynamicObjectCollection fromColls = (DynamicObjectCollection)from.get(name);
				for (DynamicObject coll : fromColls) {
					DynamicObject mulBaseData = new DynamicObject(toDynamicObjectType);
					copyChange2SrcByVersionRelData(srcEntity, changeEntity, coll, mulBaseData, rels, relObjList, tplPkId);
					primaryKey.resetValue(mulBaseData);
					toColls.add(mulBaseData);
				}
			}//字段处理
			else {
				if(from.get(name) == null) {
					continue;
				}
				if("id".equals(name) || "billno".equals(name)) {
					continue;
				}
				to.set(name, from.get(name));
			}
		}
	}
	
}
