package nc.service.rest.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.sec.esapi.NCESAPI;
import nc.itf.gl.voucher.IVoucher;
import nc.itf.uap.IUAPQueryBS;
import nc.jdbc.framework.SQLParameter;
import nc.jdbc.framework.processor.BeanListProcessor;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.service.rest.base.NcToNccBaseRestService;
import nc.service.rest.utils.ConvertVoucherUtil;
import nc.service.rest.utils.TranslateVoucherUtil;
import nc.vo.gl.closeaccbook.CloseaccbookVO;
import nc.vo.gl.pubvoucher.VoucherVO;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDate;
import nc.vo.pubapp.AppContext;
import nccloud.commons.lang.StringUtils;
import nccloud.pubitf.gl.lightgl.voucher.IVoucherWebService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * 推送NCC凭证接口：接收并保存NC63推送的凭证
 * 2020-11-12
 * @version NCC2005
 */
@SuppressWarnings("restriction")
public class PushVoucherRestService extends NcToNccBaseRestService {

	private static final long serialVersionUID = 1L;
	private BaseDAO dao = new BaseDAO();
	private IVoucherWebService service = NCLocator.getInstance().lookup(IVoucherWebService.class);

	@Override
	protected Object execute(JSONObject json) throws Exception {

		// 1.获取报文数据，转换成凭证VO
		JSONArray data = json.getJSONArray("data");
		List<VoucherVO> vouchers = ConvertVoucherUtil.jsonToVoucherVOList(data);

		// 2.凭证VO按不同账簿分类
		Map<String, List<VoucherVO>> voListMap = classifyVoucherVO(vouchers);

		
		JSONArray jsonArray = new JSONArray();
		String paraSql = "SELECT value FROM pub_sysinit WHERE initcode ='GL140' and nvl(dr,0)=0 "; 
		String para = (String) this.dao.executeQuery(paraSql, new ColumnProcessor());
		
		Iterator<Map.Entry<String, List<VoucherVO>>> iterator = voListMap.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<String, List<VoucherVO>> entry = iterator.next();
			List<VoucherVO> voList = entry.getValue();
			// 3.编码翻译成主键
			new TranslateVoucherUtil().translateCode2Key(voList);
			// 4.新增凭证
			List<String> pkList = new ArrayList<String>();
			if(null != para && para.equals("Y")) {
				for (VoucherVO voucher : voList) {
					//2021-01-17校验是否已经生成凭证
					String voucherSql = "select pk_voucher from gl_voucher where free3 = '"+voucher.getFree3()+"' and nvl(dr,0) =0 and pk_org = '"+ voucher.getPk_org() +"'";
					String pk_voucher = (String) NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(voucherSql,new ColumnProcessor());
					if(StringUtils.isEmpty(pk_voucher)) {
						if (voucher.getPk_prepared() != null) {
							InvocationInfoProxy.getInstance().setUserId(voucher.getPk_prepared()); // 制单人设置为当前用户
						}
						//校验是否关账、结账
						String returnMsg = closeAccbook(voucher.getPk_org(),voucher.getPrepareddate());
						if(StringUtils.isEmpty(returnMsg)) {
							UFDate businessDate = AppContext.getInstance().getBusiDate(); // 业务日期
							service.insertVoucher(voucher, true, businessDate);
						}else {
							throw new BusinessException(returnMsg);
						}
					}
				}
			}else {
				//_start add by hanmh 凭证签字状态删除报错2021-01-08
				for (VoucherVO voucher : voList) {
					String pk_checked = voucher.getPk_checked();//审核人
					String manager = voucher.getPk_manager();//记账人
					JSONObject returnjson = new JSONObject();
					//2021-01-17校验是否已经生成凭证
					String voucherSql = "select pk_voucher from gl_voucher where free3 = '"+voucher.getFree3()+"' and nvl(dr,0) =0 and pk_org = '"+ voucher.getPk_org() +"'";
					String pk_voucher = (String) NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(voucherSql,new ColumnProcessor());
					if(StringUtils.isEmpty(pk_voucher)) {
						//校验是否关账、结账
						String returnMsg = closeAccbook(voucher.getPk_org(),voucher.getPrepareddate());
						if(StringUtils.isEmpty(returnMsg)) {
							/*if(StringUtils.isEmpty(voucher.getPk_prepared()) && !StringUtils.isEmpty(voucher.getPk_checked()) && !StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证制单人在NCC系统不存在，请确认后继续操作！");
							}else if(StringUtils.isEmpty(voucher.getPk_prepared()) && StringUtils.isEmpty(voucher.getPk_checked()) && !StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证制单人、审核人在NCC系统不存在，请确认后继续操作！");
							}else if(StringUtils.isEmpty(voucher.getPk_prepared()) && !StringUtils.isEmpty(voucher.getPk_checked()) && StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证制单人、记账人在NCC系统不存在，请确认后继续操作！");
							}else if(StringUtils.isEmpty(voucher.getPk_prepared()) && StringUtils.isEmpty(voucher.getPk_checked()) && StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证制单人、审核人、记账人在NCC系统不存在，请确认后继续操作！");
							}else if(!StringUtils.isEmpty(voucher.getPk_prepared()) && StringUtils.isEmpty(voucher.getPk_checked()) && !StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证审核人在NCC系统不存在，请确认后继续操作！");
							}else if(!StringUtils.isEmpty(voucher.getPk_prepared()) && StringUtils.isEmpty(voucher.getPk_checked()) && StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证审核人、记账人在NCC系统不存在，请确认后继续操作！");
							}else if(!StringUtils.isEmpty(voucher.getPk_prepared()) && !StringUtils.isEmpty(voucher.getPk_checked()) && StringUtils.isEmpty(voucher.getPk_manager())) {
								throw new BusinessException("凭证记账人在NCC系统不存在，请确认后继续操作！");
							}*/
							if(StringUtils.isEmpty(voucher.getPk_prepared())){
								throw new BusinessException("凭证制单人在NCC系统不存在，请确认后继续操作！");
							}
							if (voucher.getPk_prepared() != null) {
								InvocationInfoProxy.getInstance().setUserId(voucher.getPk_prepared()); // 制单人设置为当前用户
							}
							UFDate businessDate = AppContext.getInstance().getBusiDate(); // 业务日期
							voucher.setPk_checked(null);
							voucher.setPk_manager(null);
							service.insertVoucher(voucher, true, businessDate);
							
							pkList.add(voucher.getPk_voucher());
							//凭证审核
							InvocationInfoProxy.getInstance().setUserId(pk_checked);
							//先取消审核service.checkVoucher(pkList.toArray(new String[1]), true, true);
							//凭证记账
							InvocationInfoProxy.getInstance().setUserId(manager);
							//先取消记账service.tallyVoucher(pkList.toArray(new String[1]), AppContext.getInstance().getBusiDate().toString(), true, true);
							Properties props = new Properties();
							InvocationInfoProxy.getInstance().setUserId(props.getProperty("user_id"));
							String updateSql = "update gl_voucher set signflag='N',free4='"+voucher.getFree2()+"' where nvl(dr,0) = 0 and pk_voucher ='"+voucher.getPk_voucher()+"' ";
							new BaseDAO().executeUpdate(updateSql);
							returnjson.put("msg", "NCC成功保存NC推送的凭证");
							returnjson.put("pkValue", voucher.getFree3());
							returnjson.put("nccvoucherno", voucher.getAttributeValue("num"));
							jsonArray.add(returnjson);
						}else {
							throw new BusinessException(returnMsg);
						}
						//_end add by hanmh 凭证签字状态删除报错2021-01-08
					}else {
						VoucherVO vouchervo = NCLocator.getInstance().lookup(IVoucher.class).findByPrimaryKey(pk_voucher);
						returnjson.put("msg", "NCC成功保存NC推送的凭证");
						returnjson.put("pkValue", voucher.getFree3());
						returnjson.put("nccvoucherno", vouchervo.getAttributeValue("num"));
						jsonArray.add(returnjson);
					}
				}
			}
		}
		if(StringUtils.isEmpty(para) || para.equals("N")) {
			return jsonArray;
		}else {
			return "NCC成功保存NC推送的凭证";
		}
	}
	
	private String closeAccbook(String pk_org, UFDate prepareddate) throws BusinessException {
		String yearmth = prepareddate.toString().substring(0, 7);
		String lastYearmonth = null;
		int month = prepareddate.getMonth();
		if(month == 1){
			int year = prepareddate.getYear();
			int lastYear = year - 1;
			lastYearmonth = lastYear +"-12";
		}else {
			int lastMonth = month - 1;
			if(month <= 10) {
				lastYearmonth = prepareddate.getYear() +"-0"+lastMonth;
			}else {
				lastYearmonth = prepareddate.getYear() +"-"+lastMonth;
			}
		}
		//校验当月是否关账，上月是否关账
		String accSql = "SELECT yearmth FROM bd_accperiodmonth where pk_accperiodmonth in(SELECT pk_accountperiod FROM org_accountingbook where pk_relorg ='"+pk_org+"' and nvl(dr,0)=0)and nvl(dr,0)=0\r\n" ;
		//组织建账期间
		String accountperiod  = (String) NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(accSql,new ColumnProcessor());
		//凭证时间大于建账期间，就校验上个月是否关账、是否结账
		String isendacclast = getValueFromPara("isendacc",pk_org,lastYearmonth);//上月结账状态
		if(StringUtils.isEmpty(accountperiod)) {
			return"NCC系统未建账，请确认后继续操作！";
		}else {
			if(new UFDate(yearmth+"-01").compareTo(new UFDate(accountperiod+"-01")) > 0) {
				String lastCloseaccSql = "SELECT * FROM org_closeacc WHERE pk_org ='"+pk_org+"' AND pk_accperiodmonth in(SELECT pk_accperiodmonth  FROM bd_accperiodmonth WHERE yearmth='"+lastYearmonth+"' AND nvl(dr,0)=0) AND moduleid='2002'AND nvl(dr,0)=0\r\n" ;
				List<CloseaccbookVO> lastAccbookvoList = (List<CloseaccbookVO>)NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(lastCloseaccSql,new BeanListProcessor(CloseaccbookVO.class));
				//校验上个月关账、结账情况
				if(null == lastAccbookvoList || lastAccbookvoList.size() == 0) {
					return"NCC系统上个月未关账、未结账，请确认后继续操作！";
				}else {
					if(null == lastAccbookvoList.get(0).getIsclose() || !lastAccbookvoList.get(0).getIsclose().booleanValue()) {
						return"NCC系统上个月未关账，请确认后继续操作！";
					}else if(StringUtils.isEmpty(isendacclast) || "N".equalsIgnoreCase(isendacclast)){
						return"NCC系统上个月未结账，请确认后继续操作！";
					}else if((null == lastAccbookvoList.get(0).getIsclose() || !lastAccbookvoList.get(0).getIsclose().booleanValue()) && (StringUtils.isEmpty(isendacclast) || "N".equalsIgnoreCase(isendacclast))) {
						return"NCC系统上个月未关账、未结账，请确认后继续操作！";
					}
				}
			}else if(new UFDate(yearmth+"-01").compareTo(new UFDate(accountperiod+"-01")) < 0) {
				return"NCC系统未建账，请确认后继续操作！";
			}
		}
		String closeaccSql = "SELECT * FROM org_closeacc WHERE pk_org ='"+pk_org+"' AND pk_accperiodmonth in(SELECT pk_accperiodmonth  FROM bd_accperiodmonth WHERE yearmth='"+yearmth+"' AND nvl(dr,0)=0) AND moduleid='2002'AND nvl(dr,0)=0\r\n" ;
		List<CloseaccbookVO> accbookvoList = (List<CloseaccbookVO>)NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(closeaccSql,new BeanListProcessor(CloseaccbookVO.class));
		//校验当月关账、结账情况
		String isendacc = getValueFromPara("isendacc",pk_org,yearmth);//当月结账状态
		if((null != accbookvoList && accbookvoList.size() != 0)) {
			if(null != accbookvoList.get(0).getIsclose() && accbookvoList.get(0).getIsclose().booleanValue()) {
				return"NCC系统已关账，请确认后继续操作！";
			}else if(!StringUtils.isEmpty(isendacc) && "Y".equalsIgnoreCase(isendacc)){
				return"NCC系统已结账，请确认后继续操作！";
			}else if((null != accbookvoList.get(0).getIsclose() && accbookvoList.get(0).getIsclose().booleanValue()) && !StringUtils.isEmpty(isendacc) && "Y".equalsIgnoreCase(isendacc)) {
				return"NCC系统已关账、已结账，请确认后继续操作！";
			}
		}
		return null;
	}

	private String getValueFromPara(String flag, String pk_org, String yearmth) throws BusinessException {
		String flagSql = "SELECT "+flag+" FROM org_closeacc WHERE pk_org ='"+pk_org+"' AND pk_accperiodmonth in(SELECT pk_accperiodmonth  FROM bd_accperiodmonth WHERE yearmth='"+yearmth+"' AND nvl(dr,0)=0) AND moduleid='2002'AND nvl(dr,0)=0\r\n" ;
		String paraValue = (String)NCLocator.getInstance().lookup(IUAPQueryBS.class).executeQuery(flagSql,new ColumnProcessor());
		if(StringUtils.isEmpty(paraValue)) {
			return null;
		}
		return paraValue;
	}

	/**
	 * 将批量推送的凭证VO，按核算账簿分类；
	 * VO翻译需要根据账簿来翻译，不同账簿的凭证VO需要分开翻译）
	 * 
	 * @param vos
	 * @return
	 */
	public Map<String, List<VoucherVO>> classifyVoucherVO(List<VoucherVO> vos) {
		Map<String, List<VoucherVO>> result = new HashMap<String, List<VoucherVO>>();
		for (VoucherVO vo : vos) {
			String pk_accbook = vo.getPk_accountingbook();
			if (result.containsKey(pk_accbook)) {
				result.get(pk_accbook).add(vo);
			} else {
				List<VoucherVO> list = new ArrayList<VoucherVO>();
				list.add(vo);
				result.put(pk_accbook, list);
			}
		}
		return result;
	}
	
	@Override
	public void exeBoforeLog(HttpServletRequest request, JSONObject json) throws Exception {
		String billCode = getBillCodes(json); // 单据号

		// 1.删除当前单据已有日志（重复推送的场景）
		String deleteSql = "delete from push_voucher_log where billcode='" + NCESAPI.sqlEncode("C_" + billCode) + "'";
		this.dao.executeUpdate(deleteSql);

		// 2. 新增日志信息
		String insertSql = "insert into push_voucher_log(billcode,description,status,json_data) values(?,?,?,?)";
		SQLParameter params = new SQLParameter();
		params = new SQLParameter();
		params.addParam("C_" + billCode);
		params.addParam("NCC收到推送凭证请求");
		params.addParam("processing"); // 状态：处理中
		params.addParam(json.toJSONString()); // 报文数据
		this.dao.executeUpdate(insertSql, params);
	}

	@Override
	public void exeAfterLog(HttpServletRequest request, JSONObject json) throws Exception {
		String billCode = getBillCodes(json); // 单据号
		String status = "success";
		String description = "NCC成功保存推送凭证";
		String sql = "update push_voucher_log set description='" + NCESAPI.sqlEncode(description) + "',status='"
				+ NCESAPI.sqlEncode(status) + "' where billcode='" + NCESAPI.sqlEncode("C_" + billCode) + "'";
		this.dao.executeUpdate(sql);
	}

	@Override
	public void businessErrorLog(HttpServletRequest request, JSONObject json, String errorMsg) throws Exception {
		String billCode = getBillCodes(json); // 单据号
		String status = "failure"; // 状态：失败
		String description = "NCC处理推送凭证时出现业务异常";
		String sql = "update push_voucher_log set description='" + NCESAPI.sqlEncode(description) + "',status='"
				+ NCESAPI.sqlEncode(status) + "',error_msg='" + NCESAPI.sqlEncode(errorMsg) + "' where billcode='"
				+ NCESAPI.sqlEncode("C_" + billCode) + "'";
		this.dao.executeUpdate(sql);
	}
	
	/**
	 * 获取凭证目标单据号
	 * @param json
	 * @return
	 */
	public String getBillCodes(JSONObject json) throws BusinessException {
		JSONArray data = json.getJSONArray("data");
		if (data == null || data.size() == 0) {
			return "~";
		}
		StringBuffer result = new StringBuffer(); // 凭证目标单据号，批量情况用逗号隔开
		for (int i = 0; i < data.size(); i++) {
			String billCode = null;
			try {
				billCode = data.getJSONObject(i).getJSONObject("data").getJSONObject("headitem").getString("free2");
			} catch (Exception e) {
				throw new BusinessException("JSON报文格式错误");
			}
			result.append((i == data.size() - 1) ? billCode : (billCode + ","));
		}
		return result.toString().trim();
	}

}
