package com.pcloud.book.book.biz.impl;

import com.pcloud.book.base.enums.BookFreezeEnum;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.biz.BookFreezeBiz;
import com.pcloud.book.book.biz.BookFundBiz;
import com.pcloud.book.book.dao.BookFreezeDao;
import com.pcloud.book.book.dao.BookFundDao;
import com.pcloud.book.book.dto.BookDto;
import com.pcloud.book.book.dto.BookFreezeDto;
import com.pcloud.book.book.dto.BookFundDetailDto;
import com.pcloud.book.book.dto.BookFundDto;
import com.pcloud.book.book.dto.BookFundInfoDto;
import com.pcloud.book.book.entity.BookFund;
import com.pcloud.book.book.entity.ThawEarning;
import com.pcloud.book.book.vo.BookFreezeInfoDto;
import com.pcloud.book.consumer.erp.ErpConsr;
import com.pcloud.book.elasticsearch7.domain.entity.Es7BookFreeze;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.core.constant.MQTopicProducer;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.page.PageBean;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.string.StringUtil;

import org.apache.commons.lang.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.val;

/**
 * @描述：书刊基金业务实现层
 * @作者：lihao
 * @创建时间：2017年7月19日,下午3:14:10 @版本：1.0
 */
@Service("bookFundBiz")
public class BookFundBizImpl implements BookFundBiz {

	private static final Logger LOGGER = LoggerFactory.getLogger(BookFundBizImpl.class);

	@Autowired
	private BookFundDao bookFundDao;
	@Autowired
	private ErpConsr erpConsr;
	@Autowired
	private BookFreezeDao bookFreezeDao;
	@Autowired
	private AmqpTemplate amqpTemplate;

	/**
	 * 创建书刊基金状态
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void create(BookFund bookFund) {
		LOGGER.info("【书刊管理(平台端)】创建书刊基金状态,<START>.[bookFund]:{}" , bookFund);
		// 参数校验
		this.checkAddParam(bookFund);
		// 判断有效期是否重复
		this.timeIsExsit(bookFund);
		try {
			bookFundDao.insert(bookFund);
			//同步到erp,找endTime最大的一个
			synErp(bookFund.getBookId());
		} catch (Exception e) {
			LOGGER.error("【书刊管理(平台端)】创建书刊基金状态,<ERROR>.[bookFundDao.insert]" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "创建书刊基金状态失败！");
		}
	}

	private void synErp(Long bookId) {
		BookFundDto dto=bookFundDao.getMaxEndTimeByBookId(bookId);
		if(null!=dto) {
			//如果endTime最大的一个复合要求就同步
			if (new Date().before(dto.getEndTime())){
				erpConsr.addFund(bookId, DateUtil.formatDateTime(dto.getStartTime()), DateUtil.formatDateTime(dto.getEndTime()), dto.getFundName(), dto.getPurchaseMoney(),dto.getBatchNumber());
			} else {
				//否则删除
				erpConsr.deleteFund(bookId);
			}
		}
	}

	/**
	 * 修改刊基金状态
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void update(BookFund bookFund) {
		LOGGER.info("【书刊管理(平台端)】修改刊基金状态,<START>.[bookFund]:{}", bookFund);
		if (null == bookFund.getBookFundId()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金标识不能为空！");
		}
		if (null == bookFund.getEndTime()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金结束时间不能为空！");
		}
		BookFundDto bookFundDto = bookFundDao.getByBookFundId(bookFund.getBookFundId());
		if (null == bookFundDto) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "该基金不存在！");
		}
		bookFund.setStartTime(DateUtils.formatDate(bookFundDto.getStartTime()));
		// 判断有效期是否重复
		this.timeIsExsit(bookFund);
		try {
			bookFundDao.update(bookFund);
			//同步到erp,找endTime最大的一个
			synErp(bookFund.getBookId());
		} catch (Exception e) {
			LOGGER.error("【书刊管理(平台端)】修改刊基金状态,<ERROR>.[bookFundDao.insert]" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "修改刊基金状态失败！");
		}
	}

	/**
	 * 校验参数
	 */
	private void checkAddParam(BookFund bookFund) throws BizException {

		if (null == bookFund.getBookId()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书籍标识码不能为空！");
		}
		if (StringUtil.isEmpty(bookFund.getFundName())) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金名称不能为空！");
		}
		if (null == bookFund.getPurchaseMoney()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金购买金额不能为空！");
		}
		if (null == bookFund.getStartTime()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金开始时间不能为空！");
		}
		if (null == bookFund.getEndTime()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金结束时间不能为空！");
		}
		if(null!=bookFund.getFromErp()){
			return;
		}
		if(StringUtil.isEmpty(bookFund.getContractNo())){
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "挂牌/合同编号不能为空！");
		}
		if(StringUtil.isEmpty(bookFund.getBatchNumber())){
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "批次号不能为空！");
		}
		if(bookFund.getContractNo().length()>30){
			throw new BookBizException(BookBizException.PARAM_IS_ERROR, "挂牌/合同编号长度过长！");
		}
		if(bookFund.getBatchNumber().length()>30){
			throw new BookBizException(BookBizException.PARAM_IS_ERROR, "批次号长度过长！");
		}
	}

	/**
	 * 判断基金购买有效期是否重复
	 */
	private void timeIsExsit(BookFund bookFund) throws BizException {
		Long bookId = bookFund.getBookId();
		List<BookFundDto> bookFundDtos = null;
		if (bookFund.getBookFundId() == null) {// 新增
			bookFundDtos = bookFundDao.getByBookId(bookId);
		} else { // 修改
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("bookId", bookId);
			paramMap.put("bookFundId", bookFund.getBookFundId());
			bookFundDtos = bookFundDao.getFundListByMap(paramMap);
		}
		if (null != bookFundDtos && bookFundDtos.size() != 0) {
			Long sTime = DateUtils.StringToDateTime(bookFund.getStartTime()).getTime();// 未加开始时间
			Long eTime = DateUtils.StringToDateTime(bookFund.getEndTime()).getTime();// 未加结束时间
			for (BookFundDto bookFundDto : bookFundDtos) {
				Long startTime = bookFundDto.getStartTime().getTime();// 已加开始时间
				Long endTime = bookFundDto.getEndTime().getTime();// 已加结束时间
				try {
					if (startTime < sTime && sTime < endTime) {// 未加开始时间不在已加有效期之内，否则重复
						throw new BookBizException(BookBizException.PARAM_IS_EXIST, "基金支持有效期已存在！");
					}
					if (startTime < eTime && eTime < endTime) {// 未加结束时间不在已加有效期之内，否则重复
						throw new BookBizException(BookBizException.PARAM_IS_EXIST, "基金支持有效期已存在！");
					}
					if (sTime < startTime && startTime < eTime) {// 已加开始时间不在未加有效期之内，否则重复
						throw new BookBizException(BookBizException.PARAM_IS_EXIST, "基金支持有效期已存在！");
					}
					if (sTime < endTime && endTime < eTime) {// 已加结束时间不在未加有效期之内，否则重复
						throw new BookBizException(BookBizException.PARAM_IS_EXIST, "基金支持有效期已存在！");
					}
					if (sTime.equals(startTime) && eTime.equals(endTime)) {// 已加有效期与未加有效期相同
						throw new BookBizException(BookBizException.PARAM_IS_EXIST, "基金支持有效期已存在！");
					}

				} catch (BookBizException e) {
					throw new BookBizException(BookBizException.PARAM_IS_EXIST,
							bookFundDto.getFundName() + "已经购买了" + DateUtils.getShortDateStr(bookFundDto.getStartTime())
									+ "至" + DateUtils.getShortDateStr(bookFundDto.getEndTime()) + "时间段的收益，不能设置重叠时间");
				}
			}
		}
	}

	/**
	 * 根据BookId获取基金状态
	 */
	@Override
	public List<BookFundDto> getByBookId(Long bookId) {
		LOGGER.info("【书刊管理(平台端)】根据BookId:{}获取基金状态,", bookId);
		if (null == bookId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书籍标识不能为空！");
		}
		List<BookFundDto> bookFundDtos = bookFundDao.getByBookId(bookId);
		return bookFundDtos;
	}

	/**
	 * 判断书刊基金是否被买断
	 */
	@Override
	public Boolean isFundOccupy(Long bookId, String date) {
		if (null == bookId || null == date) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "参数缺失！");
		}
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		paramMap.put("date", date);
		List<BookFundDto> bookFundDto = bookFundDao.getByParamMap(paramMap);
		Boolean isOcuppy = false;
		if (null != bookFundDto && bookFundDto.size() != 0) {
			isOcuppy = true;
		}
		LOGGER.info("【书刊管理(内部)】判断书刊基金是否被买断,bookId:{};date:{};bookFundDto:{};isOcuppy:{}", bookId, date, bookFundDto, isOcuppy);
		return isOcuppy;
	}

	/**
	 * 编辑端获取基金买断信息
	 */
	@Override
	public Map<String, Object> getFundList4Adviser(Long bookId) {
		LOGGER.info("【书刊管理(编辑端)】编辑端获取基金买断信息,bookId:{}", bookId);
		if (null == bookId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书籍标识不能为空！");
		}
		Map<String, Object> reultMap = new HashMap<>();
		Boolean isOcuppy = null;
		// 获取当前书刊基金状态
		List<BookFundDto> bookFundDto = bookFundDao.getCurrentBookFund(bookId);
		// 已买断状态
		if (null != bookFundDto && bookFundDto.size() != 0) {
			isOcuppy = true;
			reultMap.put("isOcuppy", isOcuppy);
			reultMap.put("bookFundDto", bookFundDto);
		} else {// 未买断状态
			isOcuppy = false;
			reultMap.put("isOcuppy", isOcuppy);
			reultMap.put("bookFundDto", new ArrayList<>());
		}
		return reultMap;
	}

	/**
	 * 批量获取书刊基金总额
	 */
	@Override
	public Map<Long, BigDecimal> getBookFundMoney(List<Long> bookIds) {
		LOGGER.info("【书刊管理(编辑端)】批量获取书刊基金总额,bookIds:{}", bookIds);
		if (null == bookIds || bookIds.size() == 0) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书籍标识不能为空！");
		}
		Map<Long, BookFundDto> bookFundDtoMap = bookFundDao.getBookFundMoney(bookIds);
		Map<Long, BigDecimal> bookFundMap = new HashMap<>();
		for (Map.Entry<Long, BookFundDto> entry : bookFundDtoMap.entrySet()) {
			if (entry.getValue() != null) {
				bookFundMap.put(entry.getKey(), entry.getValue().getFundMoneySum());
			}
		}
		return bookFundMap;
	}

	/**
	 * 获取图书在基金支持的基金名称
	 */
	@Override
	public String getUseFundName(Long bookId, String useDate) {
		LOGGER.info("【内部】 获取图书在基金支持的基金名称,<START>.[bookId]=" + bookId + "useDate" + useDate);
		if (bookId == null || useDate == null) {
			return null;
		}
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		paramMap.put("useDate", useDate);
		return bookFundDao.getUseFundName(paramMap);
	}

	/**
	 * 根据BookId获取基金状态
	 */
	@Override
	public PageBean listByBookId(PageParam pageParam, Long bookId) {
		LOGGER.info("根据BookId获取基金状态,bookId:{}", bookId);
		if (null == bookId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书籍标识不能为空！");
		}
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		PageBean pageBean = bookFundDao.listPage(pageParam, paramMap, "listByBookId");
		return pageBean;
	}

	/**
	 * 正在基金支持的图书
	 */
	@Override
	public Long getHaveFundBook(List<Long> bookIds) {
		LOGGER.info("正在基金支持的图书,<START>.[bookIds]:{}", bookIds);
		if (ListUtils.isEmpty(bookIds)) {
			return null;
		}
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookIds", bookIds);
		Long bookId = bookFundDao.getHaveFundBook(paramMap);
		return bookId;
	}

	/**
	 * 获取书刊基金状态
	 */
	@Override
	public BookFundDto getByBookFundId(Long bookFundId) {
		LOGGER.info("获取书刊基金状态,<START>.[bookFundId]=" + bookFundId);
		if (null == bookFundId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金标识不能为空！");
		}
		return bookFundDao.getByBookFundId(bookFundId);
	}

	/**
	 * 删除书刊基金
	 */
	@Override
	public void deleteById(Long bookFundId) {
		LOGGER.info("删除书刊基金,<START>.[bookFundId]=" + bookFundId);
		if (null == bookFundId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "基金标识不能为空！");
		}
		BookFundDto bookFundDto = bookFundDao.getByBookFundId(bookFundId);
		bookFundDao.deleteById(bookFundId);
		//同步到erp
		List<BookFundDto> list = bookFundDao.getByBookId(bookFundDto.getBookId());
		if(CollUtil.isEmpty(list)){
			//如果都没有了
			erpConsr.deleteFund(bookFundDto.getBookId());
		}else{
			//如果还有就同步最后一个
			synErp(bookFundDto.getBookId());
		}
	}

	/**
	 * 正在基金支持的图书列表
	 */
	@Override
	public List<Long> listHaveFundBooks(List<Long> bookIds) {
		LOGGER.info("正在基金支持的图书列表,bookIds：{}", bookIds);
		if (ListUtils.isEmpty(bookIds)) {
			return null;
		}
		List<Long> fundBookIds = bookFundDao.listHaveFundBooks(bookIds);
		return fundBookIds;
	}

	/**
	 * 获取所有正在基金支持的书
	 */
	@Override
	public List<Long> listAllHaveFundBooks() {
		List<Long> fundBookIds = bookFundDao.listAllHaveFundBooks();
		return fundBookIds;
	}

	@ParamLog(description = "获取图书在基金支持的基金信息【内部调用】")
	@Override
	public BookFundInfoDto getUseFundInfo(Long bookId, String useDate) {
		if (bookId == null || useDate == null) {
			return null;
		}
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		paramMap.put("useDate", useDate);
		BookFundInfoDto bookFundInfoDto = bookFundDao.getUseFundInfo(paramMap);
		return null == bookFundInfoDto? new BookFundInfoDto():bookFundInfoDto;
	}

	@Override
	@ParamLog("获取图书是否设置过基金（不计算未开始的）(内部调用)")
	public Boolean getIsHaveFundBefore(Long bookId) {
		if(bookId == null) return null;
		Boolean isHaveFundBefore = bookFundDao.getIsHaveFundBefore(bookId);
		return isHaveFundBefore;
	}

	@Override
	public Integer getFundBookCount() {
		return bookFundDao.getFundBookCount();
	}

	@Override
	public void batchCreate(BookFund bookFund) {
		LOGGER.info("【书刊管理(平台端)】批量创建书刊基金状态,<START>.[bookFund]:{}" , bookFund);
		if(CollUtil.isEmpty(bookFund.getBookIds())){
			return;
		}
		// erp逻辑，此处先解冻。
		// 可能有的没有冻结
		List<BookFund> list=new ArrayList<>();
		BookFund build=null;
		for (Long bookId : bookFund.getBookIds()) {
			//此处先解冻
			Boolean operate=true;
			BookFreezeDto bookFreezeDto = bookFreezeDao.getBaseById(bookId);
			if (bookFreezeDto!= null) {
				ThawEarning thawEarning= new ThawEarning();
				thawEarning.setBookId(bookId);
				thawEarning.setIsFund(0);
				try {
					bookFreezeDao.thaw(null,thawEarning.getBookId(), null);
				} catch (Exception e) {
					LOGGER.error("【图书收益冻结管理(erp端)】解冻收益,<ERROR>.[bookFreezeDao.thaw]" + e.getMessage(), e);
					operate=false;
				}
				if(operate) {
					thawEarning.setFreezetime(bookFreezeDto.getFreezetime());
					amqpTemplate.convertAndSend(MQTopicProducer.EXCHAGE, MQTopicProducer.BOOK_THAW, thawEarning);
				}
			}
			build=new BookFund();
			BeanUtil.copyProperties(bookFund,build,false);
			build.setBookId(bookId);
			try {
				timeIsExsit(build);
			} catch (BizException e) {
				continue;
			}
			list.add(build);
		}
		try {
			if(CollUtil.isNotEmpty(list)) {
				bookFundDao.insert(list);
			}
		} catch (Exception e) {
			LOGGER.error("【书刊管理(平台端)】批量创建书刊基金状态,<ERROR>.[bookFundDao.insert]" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "批量创建书刊基金状态失败！");
		}
	}

	@Override
	public Map<Long, BookFundDetailDto> synOldFundData(List<Long> bookIds) {
		if(CollUtil.isEmpty(bookIds)){
			return new HashMap<>();
		}
		Map<Long, BookFundDetailDto> result=new HashMap<>();
		List<BookFundDto> listByBookIds = bookFundDao.getListByBookIds(bookIds);
		Map<Long, List<BookFundDto>> bookFundMap =CollUtil.isEmpty(listByBookIds) ? new HashMap<>() : listByBookIds.stream().collect(Collectors.groupingBy(a -> a.getBookId()));
		List<BookFreezeInfoDto> bookFreezeInfoDtos = bookFreezeDao.listBookFreezeInfo(bookIds);
		Map<Long, List<BookFreezeInfoDto>> bookFreezeMap =CollUtil.isEmpty(bookFreezeInfoDtos) ? new HashMap<>() :  bookFreezeInfoDtos.stream().collect(Collectors.groupingBy(a -> a.getBookId()));
		for (Long bookId : bookIds) {
			boolean isFundSupport = false;
			Integer freezeStatus = BookFreezeEnum.WAIT_FREEZE.value;
			BookFundDetailDto dto=new BookFundDetailDto();
			if(CollUtil.isNotEmpty(bookFundMap) && bookFundMap.containsKey(bookId)){
				List<BookFundDto> bookFundDtos = bookFundMap.get(bookId);
				bookFundDtos.sort(Comparator.comparing(BookFundDto::getStartTime).reversed());
				for (BookFundDto bookFundDto : bookFundDtos) {
					Date startTime = bookFundDto.getStartTime();
					Date endTime = bookFundDto.getEndTime();
					if (new Date().before(startTime)) {
						freezeStatus = BookFreezeEnum.NO_FREEZE.value;
					} else if (new Date().after(startTime) && new Date().before(endTime)) {
						freezeStatus = BookFreezeEnum.NO_FREEZE.value;
					}
					if (new Date().before(endTime)) {
						isFundSupport = true;
					}
					//这些字段取最后一个,因为排序是从最后开始。所以第一个取到了后面就不更新了。
					if(BookFreezeEnum.NO_FREEZE.value.equals(freezeStatus) && null==dto.getStartTime()) {
						dto.setStartTime(startTime);
						dto.setEndTime(endTime);
						dto.setFundName(bookFundDto.getFundName());
						dto.setTransferor(bookFundDto.getTransferor());
						dto.setPurchaseMoney(bookFundDto.getPurchaseMoney());
					}
				}
				dto.setIsHaveFund(true);
			}
			if(CollUtil.isNotEmpty(bookFreezeMap) && bookFreezeMap.containsKey(bookId)){
				List<BookFreezeInfoDto> listFreeze = bookFreezeMap.get(bookId);
				listFreeze.sort(Comparator.comparing(BookFreezeInfoDto::getId).reversed());
				BookFreezeInfoDto bookFreezeInfoDto = listFreeze.get(0);
				if(bookFreezeInfoDto.getFreezeStatus().equals(BookFreezeEnum.FREEZE.value.intValue())){
					dto.setFreezeTime(null!=bookFreezeInfoDto.getFreezeTime() ? DateUtil.parse(bookFreezeInfoDto.getFreezeTime(), DatePattern.NORM_DATE_FORMAT) : null);
				}else{
					dto.setThawTime(null!=bookFreezeInfoDto.getThawTime() ? DateUtil.parse(bookFreezeInfoDto.getThawTime(), DatePattern.NORM_DATE_FORMAT) : null);
				}
			}
			dto.setIsFundSupport(isFundSupport);
			dto.setFreezeStatus(BooleanUtils.toIntegerObject(dto.getFreezeTime() == null,
					freezeStatus, BookFreezeEnum.FREEZE.value));
			result.put(bookId,dto);
		}
		return result;
	}

	@Override
	public Boolean checkRepeatBatchNumber(String batchNumber) {
		Integer count = bookFundDao.getCountByBatchNumber(batchNumber);
		return count > 0;
	}
}
