package nccloud.itf.sscivm.ivsale.splitmerge.processor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import nc.bs.framework.common.NCLocator;
import nc.bs.sscivm.ivsale.ivaconst.IVAPPSplitMergeConst;
import nc.bs.sscivm.logger.SSCIVMLogger;
import nc.bs.sscivm.pubconst.SSCIVMPubConst;
import nc.jdbc.framework.generator.SequenceGenerator;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDouble;
import nc.vo.sscivm.ivmpub.IVAplocationFPXZ;
import nc.vo.sscivm.ivmpub.IVAplocationKPFS;
import nc.vo.sscivm.ivmpub.InvoiceTypeEnum;
import nc.vo.sscivm.ivsale.IVApplicationAggVO;
import nc.vo.sscivm.ivsale.IVApplicationBodyVO;
import nc.vo.sscivm.ivsale.IVApplicationHeadVO;
import nc.vo.sscivm.ivsale.splitmerge.CommonPlanContext;
import nccloud.impl.platform.common.util.StringUtils;
import nccloud.itf.sscivm.ivsale.service.IVApplicationInvoiceService;
import nccloud.itf.sscivm.ivsale.service.IVApplicationQueryService;
import nccloud.itf.sscivm.ivsale.splitmerge.rule.SplitMergeBaseDocRule;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * 抽象处理实现类
 * @author wangyl7
 * @Date 2023-7-5 18:07:07
 */
public abstract class CommonProcessor {
	/**
	 * 执行处理器逻辑
	 * @param context
	 * @return
	 * @throws BusinessException
	 */
	public abstract Map<String, Object> process(CommonPlanContext context) throws BusinessException;
	
	/**
	 * 一键还原处理
	 * @param context
	 * @return
	 * @throws BusinessException
	 */
	public Map<String, Object> oneButtonRestore(CommonPlanContext context)  throws BusinessException{
		Map<String, Object> result = new HashMap<String, Object>();
		//默认打开待开票明细页面
		result.put(SSCIVMPubConst.PAGECODE, IVAPPSplitMergeConst.SQ_KPDETAIL);
		//收购标志
		result.put(IVApplicationHeadVO.SGBZ, context.getCurBills()[0].getParentVO().getSgbz().booleanValue());
		
		//按照组织，发票类型，客户/供应商/散户 进行分组
		Map<String, List<IVApplicationAggVO>> groupVosMap = groupAppVos(context.getCurBills());
		
		//对分组数据进行加工
		result.put(IVAPPSplitMergeConst.DATA, processData(groupVosMap));
		
		return result;
	}
	
	/**
	 * 预处理折扣行信息
	 * @param context
	 */
	public void prepareZkh(CommonPlanContext context) {
		for(IVApplicationAggVO appVo : context.getCurBills()) {
			int zkbz = 1;
			IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
	       	for (IVApplicationBodyVO body : bodys) {
        		//正常行直接跳过
        		if (body.getFphxz() == IVAplocationFPXZ.FPXZ_ZCH.toIntValue()) {
        			continue;
        		}
        		
        		//被折扣行也加入，同时找到对应折扣行也加入，并建立对应关联关系
        		if (body.getFphxz() == IVAplocationFPXZ.PFPXZ_BZKH.toIntValue()) {
        			//查找对应折扣行
        			for (IVApplicationBodyVO bVo : bodys) {
        				if (bVo.getFphxz() == IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
        					if (body.getZkhhh().equals(bVo.getHh())) {
        						bVo.setZkhhh(IVAPPSplitMergeConst.ZKH + ":" + zkbz);
        	        			break;
        					}
        				}
        			}
        			//标记被折扣行并加入
        			body.setZkhhh(IVAPPSplitMergeConst.BZKH + ":" + zkbz);
        			zkbz++;
        		}
        	}
		}
	}
	
	/**
	 * 按照组织，发票类型，客户/供应商/散户 进行分组
	 * @param appVos
	 * @return
	 * @throws BusinessException
	 */
    public Map<String, List<IVApplicationAggVO>> groupAppVos(IVApplicationAggVO[] appVos) throws BusinessException{
    	Map<String, List<IVApplicationAggVO>> groupVosMap = new HashMap<String, List<IVApplicationAggVO>>();
    	for (IVApplicationAggVO appVo : appVos) {
    		IVApplicationHeadVO headVo = appVo.getHeadVO();
    		//组装key key = 组织 + 发票类型 + 客户/供应商/散户
    		//散户为空，收购申请取供应商，其他申请取客户
    		String key = headVo.getPk_org() + headVo.getFplx() + headVo.getTspz();
    		if (StringUtils.isEmpty(headVo.getPk_freecustom())) {
    			//收购
    			if (headVo.getSgbz().booleanValue()) {
    				key += headVo.getPk_supplier();
    			} else {
    				//其他
    				key += headVo.getPk_customer();
    			}
    		} else {
    			key += headVo.getPk_freecustom();
    		}
    		
    		//key一致的归为一组
    		List<IVApplicationAggVO> appVoList = groupVosMap.get(key);
    		if (appVoList == null) {
    			appVoList = new ArrayList<IVApplicationAggVO>();
    		}
    		appVoList.add(appVo);
    		groupVosMap.put(key, appVoList);
    	}
    	return groupVosMap;
    }
    
    /**
         * 组装数据
     * @param groupVosMap
     * @return
     * @throws BusinessException
     */
    public List<Map<String, Object>> processData(Map<String, List<IVApplicationAggVO>> groupVosMap) throws BusinessException{
    	List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();
    	//初始主键
    	int index = 1000;
    	
    	//组装分组申请数据
    	SplitMergeBaseDocRule docRule = new SplitMergeBaseDocRule(groupVosMap);
    	for (String key : groupVosMap.keySet()) {
    		Map<String, Object> dataMap = new HashMap<String, Object>();
    		//主键
    		dataMap.put(IVAPPSplitMergeConst.ID, IVAPPSplitMergeConst.KPDETAIL + index);
    		
    		//左卡数据
    		List<IVApplicationAggVO> appVos = groupVosMap.get(key);
    		Map<String, String> docMap = docRule.processDoc(appVos);
    		dataMap.put(IVAPPSplitMergeConst.LEFTCARD, docMap);
    		
    		//右侧数据
    		dataMap.put(IVAPPSplitMergeConst.RIGHTDATA, getRightData(appVos));
    		datas.add(dataMap);

			index++;
    	}
    	return datas;
    }
    
    /**
         *待开票明细获取右侧数据
     * @param appVos
     * @return
     * @throws BusinessException
     */
    private IVApplicationBodyVO[] getRightData(List<IVApplicationAggVO> appVos) throws BusinessException{
    	List<IVApplicationBodyVO> bodyVos = new ArrayList<IVApplicationBodyVO>();
    	//折扣标记
        int zkbz = 1;

        
        //遍历开票申请，初始化表体
        for (IVApplicationAggVO appVo : appVos) {
        	IVApplicationBodyVO[] bVos = appVo.getBodyVOs();
        	for (IVApplicationBodyVO bVo : bVos) {
        		//正常行直接加入
        		if (bVo.getFphxz() == IVAplocationFPXZ.FPXZ_ZCH.toIntValue()) {
        			bodyVos.add(bVo);
        		}

        		//被折扣行也加入，同时找到对应折扣行也加入，并建立对应关联关系
        		if (bVo.getFphxz() == IVAplocationFPXZ.PFPXZ_BZKH.toIntValue()) {

        			//查找对应折扣行
        			for (IVApplicationBodyVO tbVo : bVos) {
        				if (tbVo.getFphxz() == IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
        					if (bVo.getZkhhh().equals(tbVo.getHh())) {
												//标记被折扣行并加入
												bVo.setZkhhh(IVAPPSplitMergeConst.BZKH + ":" + zkbz);
												bodyVos.add(bVo);
        					    	tbVo.setZkhhh(IVAPPSplitMergeConst.ZKH + ":" + zkbz);
        	        			bodyVos.add(tbVo);
									    	zkbz++;
        	        			break;
        					}
        				}
        			}
        		}
        	}
        }

			//遍历开票申请，初始化表体
			for (IVApplicationAggVO appVo : appVos) {
				IVApplicationBodyVO[] bVos = appVo.getBodyVOs();
				int hh = 1;
				for (IVApplicationBodyVO bVo : bVos) {
					//表体单据号赋值
					bVo.setBillno(appVo.getParentVO().getBillno());

					//行号
					bVo.setHh(String.valueOf(hh));
					hh++;
				}
			}
        return bodyVos.toArray(new IVApplicationBodyVO[0]);
    }
    
    /**
       * 发票预览处理
     * @param result
     * @return
     */
    public Map<String, Object> previewDMHM(Map<String, Object> result) {
    	List<Map<String, Object>> datas = (List<Map<String, Object>>)result.get(IVAPPSplitMergeConst.DATA);
    	for (Map<String, Object> dataMap : datas) {
    		IVApplicationAggVO appVo = (IVApplicationAggVO)dataMap.get(IVAPPSplitMergeConst.RIGHTDATA);
    		if (InvoiceTypeEnum.getPaperInvoice().contains(appVo.getParentVO().getFplx())) {
    			try {
    				appVo =  NCLocator.getInstance().lookup(IVApplicationInvoiceService.class).previewFphmFpdm(appVo);
    				dataMap.put(IVAPPSplitMergeConst.RIGHTDATA, appVo);
    			} catch(Exception e) {
    				SSCIVMLogger.error(e.getMessage(), e);
    			}
    			break;
    		}
    	}
    	return result;
    }
    
    /**
	 * 计算开票申请表头金额
	 * @param appVos
	 * @return
	 */
    public List<IVApplicationAggVO> countHeadAmount(List<IVApplicationAggVO> appVos) {
	   for (IVApplicationAggVO appVo : appVos) {
		  UFDouble jshj = UFDouble.ZERO_DBL;
		  UFDouble hjje = UFDouble.ZERO_DBL;
		  UFDouble hjse = UFDouble.ZERO_DBL;
		  
		  IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
		  for (IVApplicationBodyVO body : bodys) {
			  //表体金额数量
			  body.setXmsl(body.getCaninvoice_xmsl());
			  body.setXmje(body.getCaninvoice_xmje());
			  body.setSe(body.getCaninvoice_se());
			  body.setXmjshj(body.getCaninvoice_xmjshj());
			  
			  //金额累加
			  jshj = jshj.add(body.getCaninvoice_xmjshj());
			  hjje = hjje.add(body.getCaninvoice_xmje());
			  hjse = hjse.add(body.getCaninvoice_se());
		  }
		  
		  //重置表头金额
		  IVApplicationHeadVO headVo = appVo.getHeadVO();
		  headVo.setHjje(hjje);
		  headVo.setHjse(hjse);
		  headVo.setJshj(jshj);
		  
		  headVo.setCaninvoice_hjje(hjje);
		  headVo.setCaninvoice_hjse(hjse);
		  headVo.setCaninvoice_jshj(jshj);
		  
		  //虚拟主键
		  headVo.setPk_ivapplication(new SequenceGenerator().generate());
		  //默认直联
//		  headVo.setKpfs(IVAplocationKPFS.ZLKP.toIntValue());
	   }
	   
	   return appVos;
    }

	/**
	 * 重置开票申请表体行号，建立折扣对应关系
	 * @param appVos
	 * @return
	 */
	public List<IVApplicationAggVO> resetHhWithAppId(List<IVApplicationAggVO> appVos){
		//重置行号，清空折扣行行号
		for (IVApplicationAggVO appVo : appVos) {
			IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
			int i = 1;
			for (IVApplicationBodyVO body : bodys) {
				body.setHh(String.valueOf(i));
				if (body.getFphxz() == IVAplocationFPXZ.FPXZ_ZCH.toIntValue()) {
					body.setZkhhh(null);
				}
				i++;
			}

			//被折扣行赋值
			for (IVApplicationBodyVO body : bodys) {
				if (body.getFphxz() != IVAplocationFPXZ.PFPXZ_BZKH.toIntValue()) {
					continue;
				}

				for (IVApplicationBodyVO bvo : bodys) {
					if (bvo.getFphxz() != IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
						continue;
					}
					if (body.getZkhhh().split(":")[1].equals(bvo.getZkhhh().split(":")[1]) && body.getPk_ivapplication().equals(bvo.getPk_ivapplication())) {
						body.setZkhhh(bvo.getHh());
						break;
					}
				}
			}

			for (IVApplicationBodyVO bvo : bodys){
				if (bvo.getFphxz() != IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
					continue;
				}
				bvo.setZkhhh(null);
			}
		}
		return appVos;
	}

    /**
        * 重置开票申请表体行号，建立折扣对应关系
     * @param appVos
     * @return
     */
    public List<IVApplicationAggVO> resetHh(List<IVApplicationAggVO> appVos){
    	//重置行号，清空折扣行行号
    	for (IVApplicationAggVO appVo : appVos) {
    		 IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
    		 int i = 1;
    		 for (IVApplicationBodyVO body : bodys) {
    			 body.setHh(String.valueOf(i));
    			 if (body.getFphxz() == IVAplocationFPXZ.FPXZ_ZCH.toIntValue()) {
    				 body.setZkhhh(null);
    			 }
    			 i++;
    		 }
    		 
    		 //被折扣行赋值
    		 for (IVApplicationBodyVO body : bodys) {
    			 if (body.getFphxz() != IVAplocationFPXZ.PFPXZ_BZKH.toIntValue()) {
    				 continue;
    			 }
    			 
    			 for (IVApplicationBodyVO bvo : bodys) {
    				 if (bvo.getFphxz() != IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
        				 continue;
        			 }
    				 if (body.getZkhhh().split(":")[1].equals(bvo.getZkhhh().split(":")[1])) {
    					 body.setZkhhh(bvo.getHh());
    					 break;
    				 }
    			 }
    		 }

				for (IVApplicationBodyVO bvo : bodys){
					if (bvo.getFphxz() != IVAplocationFPXZ.FPXZ_ZKH.toIntValue()) {
						continue;
					}
					bvo.setZkhhh(null);
				}
    	}
    	return appVos;
    }
    
    /**
        * 重置表体主键数据
     * @param appVos
     * @return
     * @throws BusinessException 
     */
    public List<IVApplicationAggVO> prepareDetailPk(List<IVApplicationAggVO> appVos) throws BusinessException{
    	Set<String> appIds = new HashSet<String>();
    	for (IVApplicationAggVO appVo : appVos) {
    		IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
    		for (IVApplicationBodyVO body : bodys) {
    			appIds.add(body.getPk_ivapplication());
    		}
    	}
    	
    	//建立主键和表头VO 关系
    	Map<String, IVApplicationHeadVO> map = new HashMap<String, IVApplicationHeadVO>();
    	if (appIds.size() > 0) {
    		List<IVApplicationHeadVO> headVos = NCLocator.getInstance().lookup(IVApplicationQueryService.class).queryHeadVOsByPks(appIds.toArray(new String[0]));
    		for (IVApplicationHeadVO headVo : headVos) {
    			map.put(headVo.getPk_ivapplication(), headVo);
    		}
    	}
    	
    	//重置明细主键
    	for (IVApplicationAggVO appVo : appVos) {
    		IVApplicationBodyVO[] bodys = appVo.getBodyVOs();
    		for (IVApplicationBodyVO body : bodys) {
    			JSONArray arr = new JSONArray();
    			arr.add(prepareJESl(body, map.get(body.getPk_ivapplication())));
    			body.setPk_ivappdetail(arr.toString());
    		}
    	}
   		return appVos;
    }
    	
    /**
          * 组装金额数量
      * @param needMergeVO 待合并表体
      * @return JSONObject 组装的json
      */
    public JSONObject prepareJESl(IVApplicationBodyVO bodyVo, IVApplicationHeadVO headVo){
    	JSONObject json = new JSONObject();	
    	json.put(IVApplicationBodyVO.PK_IVAPPDETAIL, bodyVo.getPk_ivappdetail());
    	json.put(IVApplicationBodyVO.XMJE,bodyVo.getXmje().doubleValue());
    	json.put(IVApplicationBodyVO.XMSL,bodyVo.getXmsl()==null?"0":bodyVo.getXmsl().doubleValue());
    	json.put(IVApplicationBodyVO.SE, bodyVo.getSe().doubleValue());
    	json.put(IVApplicationBodyVO.XMJSHJ, bodyVo.getXmjshj().doubleValue());
    	json.put(IVApplicationBodyVO.PK_IVAPPLICATION, bodyVo.getPk_ivapplication());
    	json.put(IVApplicationBodyVO.HH, bodyVo.getHh());
    	json.put(IVApplicationHeadVO.TS, headVo.getTs().toStdString());
    	return json;
   	}   
    
	/**
	 * 把行号更新到明细主键中
	 * @param bvos 明细vo
	 * @return
	 * @throws BusinessException 
	 */
	public List<IVApplicationAggVO> putHHToDetailPK(List<IVApplicationAggVO> appVos) throws BusinessException{
		Set<String> appIds = new HashSet<String>();
		for (IVApplicationAggVO appVo : appVos) {
			for(IVApplicationBodyVO bvo : appVo.getBodyVOs()){
				JSONArray arr = JSONArray.parseArray(bvo.getPk_ivappdetail());
				for(int i = 0;i < arr.size();i++){
					JSONObject json = arr.getJSONObject(i);
					appIds.add(json.getString(IVApplicationBodyVO.PK_IVAPPLICATION));
				}
			}
		}
		
    	//建立主键和表头VO 关系
    	Map<String, IVApplicationHeadVO> map = new HashMap<String, IVApplicationHeadVO>();
    	if (appIds.size() > 0) {
    		List<IVApplicationHeadVO> headVos = NCLocator.getInstance().lookup(IVApplicationQueryService.class).queryHeadVOsByPks(appIds.toArray(new String[0]));
    		for (IVApplicationHeadVO headVo : headVos) {
    			map.put(headVo.getPk_ivapplication(), headVo);
    		}
    	}
    	
    	//加入行号和时间戳
    	for (IVApplicationAggVO appVo : appVos) {
			for(IVApplicationBodyVO bvo : appVo.getBodyVOs()){
				JSONArray arr = JSONArray.parseArray(bvo.getPk_ivappdetail());
				for(int i = 0;i < arr.size();i++){
					JSONObject json = arr.getJSONObject(i);
					String pk_ivapplication = json.getString(IVApplicationBodyVO.PK_IVAPPLICATION);
					json.put(IVApplicationBodyVO.HH, bvo.getHh());
					json.put(IVApplicationHeadVO.TS, map.get(pk_ivapplication).getTs().toStdString());
				}
				bvo.setPk_ivappdetail(arr.toString());
			}
		}
		return appVos;
	}

	/**
	 * 多张开票申请合并成一张
	 * @param appVos
	 * @return
	 */
	public IVApplicationAggVO mergeAppVos(List<IVApplicationAggVO> appVos) throws BusinessException {
		//合并表体
		int index = 1;
		List<IVApplicationBodyVO> bodys = new ArrayList<>();
		StringBuffer bz = new StringBuffer();
		for (IVApplicationAggVO appVo : appVos){
			if(bz.length() == 0){
				bz.append(appVo.getParentVO().getBz());
			} else {
				bz.append("\n"+appVo.getParentVO().getBz());
			}

			IVApplicationBodyVO[] bodyVOS = appVo.getBodyVOs();
			for (IVApplicationBodyVO bodyVO : bodyVOS){
				bodys.add(bodyVO);
			}
		}
		IVApplicationAggVO appVo =  appVos.get(0);
		appVo.setChildrenVO(bodys.toArray(new IVApplicationBodyVO[0]));

		//截取备注
		if (bz != null && bz.length() > 100) {
			appVo.getParentVO().setBz(bz.toString().substring(0,100));
		}

		List<IVApplicationAggVO> vos = new ArrayList<>();
		vos.add(appVo);
		//重算表头
		vos = countHeadAmount(vos);
		//重置行号
		vos = resetHhWithAppId(vos);
		//重置表体主键数据
		vos = prepareDetailPk(vos);
		return vos.get(0);
	}

}
