/**
 * 
 */
package com.dhcc.finance.main.service.impl;

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

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dhcc.common.constant.FinanceStatusCode;
import com.dhcc.common.constant.SysConstants;
import com.dhcc.common.constant.SysStatusCode;
import com.dhcc.common.model.CurrencyMeta;
import com.dhcc.common.model.SysUserInfo;
import com.dhcc.common.model.response.RestfulResponse;
import com.dhcc.common.util.CacheDataUtil;
import com.dhcc.common.util.SnowflakeIdWorker;
import com.dhcc.finance.constant.FinanceDictConsts;
import com.dhcc.finance.main.dao.CwBdGlorgbookMapper;
import com.dhcc.finance.main.dao.CwGlBalanceMapper;
import com.dhcc.finance.main.dao.CwGlSettleMapper;
import com.dhcc.finance.main.dao.CwGlTransferExecMapper;
import com.dhcc.finance.main.dao.CwGlVoucherMapper;
import com.dhcc.finance.main.dao.CwGlVouchermaxnoMapper;
import com.dhcc.finance.main.dao.CwReverseOperationMapper;
import com.dhcc.finance.main.domain.CwBdGlorgbook;
import com.dhcc.finance.main.domain.CwGlSettle;
import com.dhcc.finance.main.domain.CwGlVouchermaxno;
import com.dhcc.finance.main.domain.CwReverseOperation;
import com.dhcc.finance.main.model.CwGlSettleAndName;
import com.dhcc.finance.main.model.CwGlTransferWeb;
import com.dhcc.finance.main.service.CwGlSettleService;
import com.dhcc.finance.util.FinanceDateUtil;
import com.dhcc.finance.util.MetaDataUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import brave.Tracer;
import lombok.extern.slf4j.Slf4j;

/**
 * @author hp
 *
 */
@Service
@Slf4j
public class CwGlSettleServiceImpl implements CwGlSettleService{
	@Autowired
	private Tracer tracer;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	CwGlSettleMapper cwGlSettleMapper;
	
	@Autowired
	CwGlTransferExecMapper cwGlTransferExecMapper;//结转信息表
	
	@Autowired
	CwGlVoucherMapper cwGlVoucherMapper;//凭证信息
	
	@Autowired
	CwGlVouchermaxnoMapper cwGlVouchermaxnoMapper;//最大凭证号表
	
	@Autowired
	CwGlBalanceMapper cwGlBalanceMapper;//辅助余额表
	
	@Autowired
	CwBdGlorgbookMapper cwBdGlorgbookMapper;//账套表
	@Autowired
	CwReverseOperationMapper cwReverseOperationMapper;//反向操作
	/* (非 Javadoc)  
	 * <p>Title: searchCwGlSettleAndName</p>  
	 * <p>Description: 查询结账信息表兼期间模糊查询</p>
	 * @param periodLike
	 * @param pageNum
	 * @param pageSize
	 * @param navigatePages
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#searchCwGlSettleAndName(java.lang.String, int, int, int)    
	 * @author huangpeng
	 * @date 2019年4月2日 下午1:41:13
	 * @修改日志：
	 */
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public RestfulResponse<PageInfo<CwGlSettleAndName>, CurrencyMeta> searchCwGlSettleAndName(String nameLike,String periodLike,
			int pageNum, int pageSize, int navigatePages,String issettle,String settleUser,String settleTime) {
		PageHelper.startPage(pageNum, pageSize);
		List<CwGlSettleAndName> list=cwGlSettleMapper.selectAllDateByName(nameLike);
		PageInfo<CwGlSettleAndName> pageInfo = new PageInfo<>(list, navigatePages);
		return new RestfulResponse<PageInfo<CwGlSettleAndName>, CurrencyMeta>(SysConstants.CODE.SUCCESS,SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS,pageInfo,MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
	}

	/* (非 Javadoc)  
	 * <p>Title: updateCwGlSettleForBatch</p>  
	 * <p>Description:批量更新结账信息 </p>
	 * @param cwGlSettles
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#updateCwGlSettleForBatch(java.util.List)    
	 * @author huangpeng
	 * @date 2019年4月2日 下午1:54:41
	 * @修改日志：
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public RestfulResponse<Object, CurrencyMeta> updateCwGlSettleForBatch(List<CwGlTransferWeb> cwGlSettles) {
		SysUserInfo sysUserInfo = CacheDataUtil.<SysUserInfo>getCacheBean(stringRedisTemplate, SysConstants.REDIS_KEY_PREFIX.SYS_USER_INFO, SysUserInfo.class);
		if(sysUserInfo==null) {
			if (StringUtils.isNotBlank(cwGlSettles.get(0).getAccounting_id())) {
				sysUserInfo = new SysUserInfo();
				sysUserInfo.setUserId("admin");
			} else {
				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,SysStatusCode.USER_LOGOUT_ERROR.message(),MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
			}
		}
		//add 2019/4/25 dml
		// 循环校验
		for (CwGlTransferWeb cwGlSettle : cwGlSettles) {
			// 查询账套信息
			CwBdGlorgbook cwBdGlorgbook = cwBdGlorgbookMapper.selectByPrimaryKey(cwGlSettle.getPkGlorgbook());
			// 页面提示信息
			String msg = cwBdGlorgbook.getName();
			// 获取上一个会计期间
			String lastMonth = FinanceDateUtil.getLastMonth(cwGlSettle.getPkCurrperiod(), "yyyy-MM",-1);
			Map<String, Object> settleMap = new  HashMap<>();
			settleMap.put("pkGlorgbook",cwGlSettle.getPkGlorgbook());
			settleMap.put("period",lastMonth);
			// 如果不是启用期间则判断上期是否结账
			if (lastMonth.equals(cwBdGlorgbook.getPkCurrperiod())) {
				// 查询上期是否结账
				Map<String, Long> res = cwGlSettleMapper.selectIssettle(settleMap);
				if (res.get("allCount") != res.get("settleCount") || res.get("settleCount") != 1 ) {
					return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,msg+FinanceStatusCode.LAST_PERIOD_NOT_SETTLE.message(),
							MetaDataUtil.getMeta(tracer,FinanceStatusCode.LAST_PERIOD_NOT_SETTLE));
				}
			}
			// 查询本期是否结转
			settleMap.put("period", cwGlSettle.getPkCurrperiod());
			Map<String, Long> selectIstransfer = cwGlTransferExecMapper.selectIstransfer(settleMap);
			if (selectIstransfer.get("allCount") != selectIstransfer.get("transferCount") || selectIstransfer.get("transferCount") != 1 ) {
				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,msg+FinanceStatusCode.CURRENT_PERIOD_CARRY_FORWARD.message(),
						MetaDataUtil.getMeta(tracer,FinanceStatusCode.CURRENT_PERIOD_CARRY_FORWARD));
			}
			// 查询该账套该期间是否已记账
			long countNotBooking = cwGlVoucherMapper.countNotBooking(cwGlSettle.getPkGlorgbook(), cwGlSettle.getPkCurrperiod());
			if (countNotBooking != 0) {
				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,msg+FinanceStatusCode.EXISTENCE_OF_UNRECORDED.message(),
						MetaDataUtil.getMeta(tracer,FinanceStatusCode.EXISTENCE_OF_UNRECORDED));
			}
//			// 查询该账套会计期间下所有凭证
//			List<CwGlVoucher> cwGlVouchers = cwGlVoucherMapper.selectForSettle(cwGlSettle.getPkGlorgbook(), cwGlSettle.getPkCurrperiod());
//			// 查询该账套该期间凭证号是否连续
//			List<CwGlVoucher> selectIsSeries = cwGlVoucherMapper.selectIsSeries(cwGlSettle.getPkGlorgbook(), cwGlSettle.getPkCurrperiod());
//			if (cwGlVouchers.size()>0 && selectIsSeries.size() != 1) {
//				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,msg+FinanceStatusCode.VOUCHER_NUMBER_DISCONTINUITY.message(),
//						MetaDataUtil.getMeta(tracer,FinanceStatusCode.VOUCHER_NUMBER_DISCONTINUITY));
//			}
			// 借贷平衡计算校验
			Map<String, BigDecimal> balanceCount = cwGlBalanceMapper.balanceCount(cwGlSettle.getPkGlorgbook(), cwGlSettle.getPkCurrperiod());
			log.info("借贷平衡计算结果>>>>>>>>>>>"+balanceCount);
			if (balanceCount.get("zcSum").compareTo(balanceCount.get("fzSum").add(balanceCount.get("syzqySum"))) !=0 ) {
				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,msg+FinanceStatusCode.ASSETS_NOTEQUAL_LIABILITIES_ALLEQUITY.message(),
						MetaDataUtil.getMeta(tracer,FinanceStatusCode.ASSETS_NOTEQUAL_LIABILITIES_ALLEQUITY));
			}
		 }
		 // 刷新辅助余额初始化最大凭证
	     for (CwGlTransferWeb cwGlSettle : cwGlSettles) {
	    	// 插入结账信息
	    	 String settlepk = SnowflakeIdWorker.getInstance().nextIdString();
			CwGlSettle cwGlSettleist = new CwGlSettle();
			if (sysUserInfo != null) {
				cwGlSettleist.setUpdateUser(sysUserInfo.getUserId());	
				cwGlSettleist.setCreateUser(sysUserInfo.getUserId());
			}
			cwGlSettleist.setPkGlorgbook(cwGlSettle.getPkGlorgbook());
			cwGlSettleist.setPeriod(cwGlSettle.getPkCurrperiod());
			cwGlSettleist.setPkSettle(settlepk);
			cwGlSettleist.setUseState(FinanceDictConsts.Syzt.EFFECTIVE);
			cwGlSettleist.setIssettle(FinanceDictConsts.Syzt.INVALID);
			cwGlSettleist.setUpdateTime(new Date());
			cwGlSettleist.setCreateTime(new Date());
			cwGlSettleMapper.insert(cwGlSettleist);
	    	// 重建科目辅助余额信息
	    	// 删除之前的辅助余额信息
	        cwGlBalanceMapper.deleteEarlyYearRecalculation(cwGlSettle.getPkGlorgbook(), cwGlSettle.getPkCurrperiod());
	        // 重算辅助余额
	        Map<String, Object> intMap = new HashMap<String, Object>();
	        intMap.put("pkGlorgbook", cwGlSettle.getPkGlorgbook());
	        intMap.put("period", cwGlSettle.getPkCurrperiod());
	        intMap.put("createUser", sysUserInfo == null? null:sysUserInfo.getUserId());
	        intMap.put("createTime", new Date());
	        cwGlBalanceMapper.insertRecalculatedBalance(intMap);
			// 获取下一个会计期间
			String nextMonth = FinanceDateUtil.getLastMonth(cwGlSettle.getPkCurrperiod(), "yyyy-MM",1);
			// 所有的凭证类型
			List<CwGlVouchermaxno> cwGlVouchermaxnoList = new ArrayList<CwGlVouchermaxno>();
			// 组成新增数据
			CwGlVouchermaxno cwGlVouchermaxno = new CwGlVouchermaxno();
			if (sysUserInfo != null) {
				cwGlVouchermaxno.setCreateUser(sysUserInfo.getUserId());
			}
			cwGlVouchermaxno.setCreateTime(new Date());
			cwGlVouchermaxno.setUseState(FinanceDictConsts.Syzt.EFFECTIVE);
			cwGlVouchermaxno.setPkVouchermaxno(SnowflakeIdWorker.getInstance().nextIdString());
			cwGlVouchermaxno.setPkGlorgbook(cwGlSettle.getPkGlorgbook());
			cwGlVouchermaxno.setPeriod(nextMonth);
			cwGlVouchermaxnoList.add(cwGlVouchermaxno);
			// 新增最大凭证信息（存在的不会在重复增加）
			cwGlVouchermaxnoMapper.insertCwGlVouchermaxnoBatch(cwGlVouchermaxnoList);
			// 组成结账信息
			CwGlSettle cwGlSettleUpd = new CwGlSettle();
			if (sysUserInfo != null) {
				cwGlSettleUpd.setUpdateUser(sysUserInfo.getUserId());	
				cwGlSettleUpd.setSettleUser(sysUserInfo.getUserId());
			}
			cwGlSettleUpd.setPkSettle(settlepk);
			cwGlSettleUpd.setIssettle(FinanceDictConsts.Syzt.EFFECTIVE);
			cwGlSettleUpd.setUpdateTime(new Date());
			cwGlSettleUpd.setSettleTime(new Date());
			// 修改结账状态
			cwGlSettleMapper.updateByPrimaryKeySelective(cwGlSettleUpd);
	    	// 查询账套信息
			CwBdGlorgbook cwBdGlorgbook = cwBdGlorgbookMapper.selectByPrimaryKey(cwGlSettle.getPkGlorgbook());
			String newCurrperiod =FinanceDateUtil.getLastMonth(cwBdGlorgbook.getPkCurrperiod(), "yyyy-MM",1);//当前会计期间加一
			cwBdGlorgbook.setPkCurrperiod(newCurrperiod);
			cwBdGlorgbookMapper.updateByPrimaryKey(cwBdGlorgbook);//结账完成后更新账套表
		}
		return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.SUCCESS,SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS,
				MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
	}

	/* (非 Javadoc)  
	 * <p>Title: searchCwGlSettleAndNameForReverse</p>  
	 * <p>Description:查询反结账信息 </p>
	 * @param nameLike
	 * @param periodLike
	 * @param pageNum
	 * @param pageSize
	 * @param navigatePages
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#searchCwGlSettleAndNameForReverse(java.lang.String, java.lang.String, int, int, int)    
	 * @author huangpeng
	 * @date 2019年4月10日 上午9:26:41
	 * @修改日志：
	 */
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public RestfulResponse<PageInfo<CwGlSettleAndName>, CurrencyMeta> searchCwGlSettleAndNameForReverse(String nameLike,
			String periodLike, int pageNum, int pageSize, int navigatePages, String issettle, String settleUser, String settleTime) {
		PageHelper.startPage(pageNum, pageSize,"CREATE_TIME DESC");
		List<CwGlSettleAndName> list=cwGlSettleMapper.selectAllDateByPeriodLike(periodLike,nameLike,"1",settleUser,settleTime);
		PageInfo<CwGlSettleAndName> pageInfo = new PageInfo<>(list, navigatePages);
		return new RestfulResponse<PageInfo<CwGlSettleAndName>, CurrencyMeta>(SysConstants.CODE.SUCCESS,SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS,pageInfo,MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
	}

	/* (非 Javadoc)  
	 * <p>Title: updateCwGlSettleForBatchReverse</p>  
	 * <p>Description:更新反结账信息 </p>
	 * @param cwGlSettles
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#updateCwGlSettleForBatchReverse(java.util.List)    
	 * @author huangpeng
	 * @date 2019年4月10日 上午9:30:31
	 * @修改日志：
	 */
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public RestfulResponse<Object, CurrencyMeta> updateCwGlSettleForBatchReverse(List<CwGlSettle> cwGlSettles) {
		SysUserInfo sysUserInfo = CacheDataUtil.<SysUserInfo>getCacheBean(stringRedisTemplate, SysConstants.REDIS_KEY_PREFIX.SYS_USER_INFO, SysUserInfo.class);
		for (CwGlSettle cwGlSettle : cwGlSettles) {	
			String period = cwGlSettle.getPeriod();
			String maxPeriod =cwGlSettleMapper.selectMaxPeriod(cwGlSettle.getPkGlorgbook());
			if(StringUtils.isNoneBlank(maxPeriod)&&period.compareTo(maxPeriod)<0) {
				CwBdGlorgbook cwBdGlorgbook = cwBdGlorgbookMapper.selectByPrimaryKey(cwGlSettle.getPkGlorgbook());
				return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL,cwBdGlorgbook.getName()+FinanceStatusCode.REVERSE_SETTLE_ISFAIL.message()+",请先反结账"+maxPeriod+"期",
						MetaDataUtil.getMeta(tracer,FinanceStatusCode.REVERSE_SETTLE_ISFAIL));
			}
			if (sysUserInfo != null) {
				cwGlSettle.setUpdateUser(sysUserInfo.getUserId());	
			}
			cwGlSettle.setIssettle("0");
			cwGlSettle.setUseState("0");
			cwGlSettle.setUpdateTime(new Date());
			cwGlSettle.setSettleTime(null);
			cwGlSettle.setSettleUser(null);
			int res =cwGlSettleMapper.updateByPrimaryKey(cwGlSettle);	
			if(res>0) {
				// 查询账套信息
				CwBdGlorgbook cwBdGlorgbook = cwBdGlorgbookMapper.selectByPrimaryKey(cwGlSettle.getPkGlorgbook());
				String newCurrperiod =FinanceDateUtil.getLastMonth(cwBdGlorgbook.getPkCurrperiod(), "yyyy-MM",-1);//当前会计期间加一
				cwBdGlorgbook.setPkCurrperiod(newCurrperiod);
				cwBdGlorgbookMapper.updateByPrimaryKey(cwBdGlorgbook);//反结账完成后更新账套表
				
				CwReverseOperation cwReverseOperation = new CwReverseOperation();
				cwReverseOperation.setPkGlorgbook(cwGlSettle.getPkGlorgbook());
				cwReverseOperation.setPeriod(cwGlSettle.getPeriod());
				if (sysUserInfo != null) {
				cwReverseOperation.setOperator(sysUserInfo.getUserId());
				}
				cwReverseOperation.setReverseType(FinanceDictConsts.Cwfxcz.FJZHANG);
				cwReverseOperation.setOperationtime(new Date());
				cwReverseOperation.setPkReverse(SnowflakeIdWorker.getInstance().nextIdString());
				cwReverseOperationMapper.insert(cwReverseOperation);//插入反结转标志
			}
		}
		return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.SUCCESS,SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS,MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
	}

	/*
	 * (非 Javadoc)  
	 * Title: countSettleTotal 
	 * Description:统计记账数
	 * @param nameLike
	 * @param periodLike
	 * @param issettle
	 * @param settleUser
	 * @param settleTime
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#countSettleTotal(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)    
	 * @author dml
	 * @date 2019年8月28日 下午9:23:46
	 * @修改日志：
	 */
	@Override
	public RestfulResponse<Object, CurrencyMeta> countSettleTotal(String nameLike, String periodLike, String issettle,
			String settleUser, String settleTime) {
		long countSettleTotal = cwGlSettleMapper.countSettleTotal(periodLike, nameLike, issettle, settleUser, settleTime);
		return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.SUCCESS,SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS,countSettleTotal,MetaDataUtil.getMeta(tracer,SysStatusCode.OPERATION_SUCCESS));
	}
	/*
	 * (非 Javadoc)  
	 * <p>Title: insertForSettle</p>  
	 * <p>Description: 初始化结账信息</p>
	 * @param period
	 * @return  
	 * @see com.dhcc.finance.main.service.CwGlSettleService#insertForSettle(java.lang.String)    
	 * @author xuxiaoxiao
	 * @date 2019年8月31日 上午10:35:00
	 * @修改日志：
	 */
	@Override
	public RestfulResponse<Object, CurrencyMeta> insertForSettle(String period) {
		SysUserInfo sysUserInfo = CacheDataUtil.<SysUserInfo>getCacheBean(stringRedisTemplate, SysConstants.REDIS_KEY_PREFIX.SYS_USER_INFO, SysUserInfo.class);
    	Map<String, Object> map =new HashMap<String, Object>();
    	map.put("createUser", sysUserInfo == null? null:sysUserInfo.getUserId());
    	map.put("updateUser", sysUserInfo == null? null:sysUserInfo.getUserId());
    	map.put("period", period);
		int res = cwGlSettleMapper.insertForSettle(map);
		if(res>0){
			return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.SUCCESS, SysConstants.DEFAULT_MESSAGE.OPERATION_SUCCESS, 
					MetaDataUtil.getMeta(tracer, SysStatusCode.OPERATION_SUCCESS));
		}else{
			return new RestfulResponse<Object, CurrencyMeta>(SysConstants.CODE.FAIL, FinanceStatusCode.ALLGLORGBOOK_IS_ADD.message(),
					MetaDataUtil.getMeta(tracer, FinanceStatusCode.ALLGLORGBOOK_IS_ADD));
		}
		
	}

}
