package com.prolog.cs.biz.inbound.service.impl.failure;

import com.prolog.cs.biz.inbound.dao.OmsAsnBillDMapper;
import com.prolog.cs.biz.inbound.dao.failure.InReceivingAbnormalDMapper;
import com.prolog.cs.biz.inbound.dao.failure.InReceivingAbnormalHMapper;
import com.prolog.cs.biz.inbound.dto.failure.RcvErrorDTO;
import com.prolog.cs.biz.inbound.dto.failure.RcvErrorQueryVO;
import com.prolog.cs.biz.inbound.model.OmsAsnBillD;
import com.prolog.cs.biz.inbound.model.failure.InReceivingAbnormalD;
import com.prolog.cs.biz.inbound.model.failure.InReceivingAbnormalH;
import com.prolog.cs.biz.inbound.service.failure.InReceivingAbnormalHService;
import com.prolog.cs.biz.inbound.utils.UserUtils;
import com.prolog.cs.data.exchange.client.ExchangeSender;
import com.prolog.cs.data.exchange.client.core.EtlMessage;
import com.prolog.cs.data.exchange.client.core.EtlTypeConstants;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class InReceivingAbnormalHImpl implements InReceivingAbnormalHService {

	@Resource
	private InReceivingAbnormalHMapper hMapper;

	@Resource
	private InReceivingAbnormalDMapper dMapper;

	@Resource
	private OmsAsnBillDMapper omsAsnBillDMapper;

	@Resource
	private ExchangeSender exchangeSender;

	@Resource
	private UserUtils userUtils;

	private static Logger log = LoggerFactory.getLogger(InReceivingAbnormalHImpl.class);

	@Override
	@Transactional
	public Object addWithRelated(RcvErrorDTO rcvErrorDTO) {
		InReceivingAbnormalH head = rcvErrorDTO.getHead();
		AssertUtils.notNull(head, "收货异常保存的头表不可为空!");
		List<InReceivingAbnormalD> detailList = rcvErrorDTO.getDetailList();
		AssertUtils.isNotEmpty(detailList, "收货异常保存的明细不可为空!");

		UserDTO userDTO = userUtils.getUserDTO();
		boolean editFlag = Boolean.FALSE;
		this.addHead(head, userDTO, editFlag);
		this.addDetails(head, detailList, userDTO, editFlag);
		return true;
	}

	private void addDetails(InReceivingAbnormalH head, List<InReceivingAbnormalD> detailList, UserDTO userDTO,
			boolean editFlag) {
		// 保存明细
		String billid = head.getBillid();
		Date now = new Date();
		int row = 0;
		for (InReceivingAbnormalD inReceivingAbnormalD : detailList) {
			row++;
			inReceivingAbnormalD.setBillid(billid);
			buildDetailDefaultField(inReceivingAbnormalD, userDTO, editFlag, now, row);
			vaildateDetail(inReceivingAbnormalD, userDTO, editFlag, now, row);
			// 校验异常收货明细行超收
			vaildateDetailOvercharge(inReceivingAbnormalD, row);
			if (!editFlag) {
				this.dMapper.save(inReceivingAbnormalD);
			} else {
				this.dMapper.updateWithValidate(inReceivingAbnormalD,
						p -> !ObjectUtils.isNull(p) && !ObjectUtils.isNull(p.getValue()));
			}
		}

		// 通知oms接收信息
		String status = head.getStatus();
		if (!status.equals("10")) {
			return;
		}
		// 需要根据asnHeaderId获取所有收货单id
		EtlMessage em = new EtlMessage();
		em.setId(billid);
		em.setEtlType(EtlTypeConstants.in_re_abnormal_w2o);
		try {
			log.info("入库异常单回传给data-exchange数据:{}", JsonUtils.toString(em));
			exchangeSender.send(em);
			log.info("入库异常单回传给data-exchange成功!");
		} catch (Exception e) {
			log.error("入库异常单回传失败,原因->{}", e);
		}
	}

	// 若是有并发的风险,建议加分布式锁,或者数据库乐观锁
	private void vaildateDetailOvercharge(InReceivingAbnormalD inReceivingAbnormalD, int row) {
		String attrStr1 = inReceivingAbnormalD.getAttrStr1();
		BigDecimal affirmedQty = inReceivingAbnormalD.getAffirmedQty();
		OmsAsnBillD omsAsnBillD = omsAsnBillDMapper.findById(attrStr1, OmsAsnBillD.class);
		AssertUtils.notNull(omsAsnBillD, String.format("异常行关联的asn单明细行id[%s]查询的数据为空!", attrStr1));
		BigDecimal itemQty = omsAsnBillD.getItemQty();
		if (affirmedQty.compareTo(itemQty) == 1) {
			throw new BizException(String.format("第[%d]行,异常收货明细超收!!!", row));
		}
	}

	private void buildDetailDefaultField(InReceivingAbnormalD inReceivingAbnormalD, UserDTO userDTO, boolean editFlag,
			Date now, int row) {
		String createby = inReceivingAbnormalD.getCreateby();
		Date createdate = inReceivingAbnormalD.getCreatedate();
		String lastmodifyby = inReceivingAbnormalD.getLastmodifyby();
		Date lastmodifydate = inReceivingAbnormalD.getLastmodifydate();
		String enterpriseid = inReceivingAbnormalD.getEnterpriseid();
		String enterprisename = inReceivingAbnormalD.getEnterprisename();
		
		String asnLineId = inReceivingAbnormalD.getAsnLineId();
		String attrStr1 = inReceivingAbnormalD.getAttrStr1();
		if (StringUtils.isBlank(attrStr1)) {
			attrStr1 = asnLineId;
		}
		inReceivingAbnormalD.setAttrStr1(attrStr1);

		String username = userDTO.getUsername();
		String enterpriseId = userDTO.getEnterpriseId();
		String enterpriseName = userDTO.getEnterpriseName();
		if (!editFlag) {
			if (StringUtils.isBlank(createby)) {
				inReceivingAbnormalD.setCreateby(username);
			}
			if (ObjectUtils.isNull(createdate)) {
				inReceivingAbnormalD.setCreatedate(now);
			}
			if (ObjectUtils.isNull(enterpriseid)) {
				inReceivingAbnormalD.setEnterpriseid(enterpriseId);
			}
			if (ObjectUtils.isNull(enterprisename)) {
				inReceivingAbnormalD.setEnterpriseid(enterpriseName);
			}
		}
		if (StringUtils.isBlank(lastmodifyby)) {
			inReceivingAbnormalD.setLastmodifyby(username);
		}
		if (ObjectUtils.isNull(lastmodifydate)) {
			inReceivingAbnormalD.setLastmodifydate(now);
		}

	}

	private void vaildateDetail(InReceivingAbnormalD detail, UserDTO userDTO, boolean editFlag, Date now, int row) {
		String billid = detail.getBillid();
		String billno = detail.getBillno();
		String lineId = detail.getLineId();
		String seqno = detail.getSeqno();
		String consignorid = detail.getConsignorid();
		String consignorcode = detail.getConsignorcode();
		String consignorname = detail.getConsignorname();
		String refbilltype = detail.getRefBilltype();
		String refbillid = detail.getRefBillid();
		String refbillcode = detail.getRefBillno();
		String refSeqno = detail.getRefSeqno();
		String itemid = detail.getItemid();
		BigDecimal totpcs = detail.getAffirmedPcs();
		BigDecimal packSize = detail.getPackSize();
		BigDecimal affirmedQty = detail.getAffirmedQty();
//		String attrStr1 = detail.getAttrStr1();
		if (!editFlag) {
			AssertUtils.isNotBlank(billid, "异常收货单id(billid)不可为空!");
			AssertUtils.isNotBlank(billno, "异常收货单编码(billno)不可为空!");
			AssertUtils.isNotBlank(seqno, "异常收货单行号(seqno)不可为空!");
			AssertUtils.isNotBlank(refSeqno, "关联入库单行号(refSeqno)不可为空!");
			AssertUtils.isNotBlank(itemid, "商品id(itemid)不可为空!");
			AssertUtils.isNotBlank(consignorid, "货主id(consignorid)不可为空!");
			AssertUtils.isNotBlank(consignorcode, "货主编码(consignorcode)不可为空!");
			AssertUtils.isNotBlank(consignorname, "货主名称(consignorname)不可为空!");
			AssertUtils.isNotBlank(refbilltype, "关联业务单类型(refbilltype)不可为空!");
			AssertUtils.isNotBlank(refbillid, "关联业务单id(refbillid)不可为空!");
			AssertUtils.isNotBlank(refbillcode, "关联业务单编码(refbillcode)不可为空!");
			AssertUtils.notNull(totpcs, "件数(affirmedPcs)不可为空!");
			AssertUtils.notNull(packSize, "包装含量(packSize)不可为空!");
//			AssertUtils.isNotBlank(attrStr1, "关联来源行id(attrStr1)不可为空!");
			AssertUtils.notNull(affirmedQty, "商品数量(affirmedQty)不可为空!");
		} else {
			AssertUtils.isNotBlank(lineId, "收货异常明细行id(lineId)不可为空!");
		}
	}

	private void addHead(InReceivingAbnormalH head, UserDTO userDTO, boolean editFlag) {
		buildHeadDefaultField(head, userDTO, editFlag);
		vaildateHead(head, userDTO, editFlag);
		if (!editFlag) {
			this.hMapper.save(head);
		} else {
			this.hMapper.updateWithValidate(head, p -> !ObjectUtils.isNull(p) && !ObjectUtils.isNull(p.getValue()));
		}
	}

	private void buildHeadDefaultField(InReceivingAbnormalH head, UserDTO userDTO, boolean editFlag) {
		String operator = head.getOperator();
		String status = head.getStatus();
		String createby = head.getCreateby();
		Date createdate = head.getCreatedate();
		String lastmodifyby = head.getLastmodifyby();
		Date lastmodifydate = head.getLastmodifydate();
		String enterpriseid = head.getEnterpriseid();
		String enterprisename = head.getEnterprisename();
		BigDecimal totpcs = head.getTotpcs();

		String username = userDTO.getUsername();
		String enterpriseId = userDTO.getEnterpriseId();
		String enterpriseName = userDTO.getEnterpriseName();
		String billid = head.getBillid();
		Date now = new Date();

		if (!editFlag) {
			if (StringUtils.isBlank(operator)) {
				head.setOperator(username);
			}
			if (StringUtils.isBlank(billid)) {
				head.setBillid(String.valueOf(SnowFlakeUtils.getId()));
			}
			if (StringUtils.isBlank(status)) {
				head.setStatus("10");
			}
			if (StringUtils.isBlank(createby)) {
				head.setCreateby(username);
			}
			if (ObjectUtils.isNull(createdate)) {
				head.setCreatedate(now);
			}
			if (ObjectUtils.isNull(enterpriseid)) {
				head.setEnterpriseid(enterpriseId);
			}
			if (ObjectUtils.isNull(enterprisename)) {
				head.setEnterpriseid(enterpriseName);
			}
			if (ObjectUtils.isNull(totpcs)) {
				head.setTotpcs(BigDecimal.ZERO);
			}
		}
		if (StringUtils.isBlank(lastmodifyby)) {
			head.setLastmodifyby(username);
		}
		if (ObjectUtils.isNull(lastmodifydate)) {
			head.setLastmodifydate(now);
		}
	}

	private void vaildateHead(InReceivingAbnormalH head, UserDTO userDTO, boolean editFlag) {
		String billid = head.getBillid();
		String billno = head.getBillno();
		String billtype = head.getBilltype();
		String branchid = head.getBranchid();
		String branchcode = head.getBranchcode();
		String branchname = head.getBranchname();
		String consignorid = head.getConsignorid();
		String consignorcode = head.getConsignorcode();
		String consignorname = head.getConsignorname();
//		String consignorBillNo = head.getConsignorBillNo();
		String refbilltype = head.getRefbilltype();
		String refbillid = head.getRefbillid();
		String refbillcode = head.getRefbillcode();
//		String purorgId = head.getPurorgId();
//		String purorgName = head.getPurorgName();
//		String buyerId = head.getBuyerId();
//		String buyerName = head.getBuyerName();
//		String arriveAddress = head.getArriveAddress();
//		String vendorcode = head.getVendorcode();
//		String vendorname = head.getVendorname();
//		String accGoodsBillNo = head.getAccGoodsBillNo();
//		String vpoNo = head.getVpoNo();
//		Date vendorReceiveDate = head.getVendorReceiveDate();
//		String vendorAddress = head.getVendorAddress();
//		String refbillno = head.getRefbillno();
		BigDecimal totpcs = head.getTotpcs();
//		BigDecimal totqty = head.getTotqty();
//		BigDecimal totnetamt = head.getTotnetamt();
//		BigDecimal totamt = head.getTotamt();
//		Date operatedate = head.getOperatedate();
//		String operator = head.getOperator();
//		String confirmer = head.getConfirmer();
//		String qtoperator = head.getQtoperator();
//		String qtoperator2 = head.getQtoperator2();
//		String rcvoperator = head.getRcvoperator();
//		String rcvoperator2 = head.getRcvoperator2();
//		String status = head.getStatus();
//		String auditResult = head.getAuditResult();
//		String auditOpinion = head.getAuditOpinion();
//		String remark = head.getRemark();
//		String attrStr1 = head.getAttrStr1();
//		String attrStr2 = head.getAttrStr2();
//		String attrStr3 = head.getAttrStr3();
//		String attrStr4 = head.getAttrStr4();
//		String attrStr5 = head.getAttrStr5();
//		BigDecimal attrNum1 = head.getAttrNum1();
//		BigDecimal attrNum2 = head.getAttrNum2();
//		Date attrDte1 = head.getAttrDte1();
//		Date attrDte2 = head.getAttrDte2();
		String createby = head.getCreateby();
		Date createdate = head.getCreatedate();
//		String lastmodifyby = head.getLastmodifyby();
//		Date lastmodifydate = head.getLastmodifydate();
//		String enterpriseid = head.getEnterpriseid();
//		String enterprisename = head.getEnterprisename();
		if (!editFlag) {
//			AssertUtils.isNotBlank(billid, "异常收货单id(billid)不可为空!");
			AssertUtils.isNotBlank(billno, "异常收货单编码(billno)不可为空!");
			AssertUtils.isNotBlank(billtype, "异常收货单类型(billtype)不可为空!");
			AssertUtils.isNotBlank(branchid, "仓库id(branchid)不可为空!");
			AssertUtils.isNotBlank(branchcode, "仓库编码(branchcode)不可为空!");
			AssertUtils.isNotBlank(branchname, "仓库名称(branchname)不可为空!");
			AssertUtils.isNotBlank(consignorid, "货主id(consignorid)不可为空!");
			AssertUtils.isNotBlank(consignorcode, "货主编码(consignorcode)不可为空!");
			AssertUtils.isNotBlank(consignorname, "货主名称(consignorname)不可为空!");
			AssertUtils.isNotBlank(refbilltype, "关联业务单类型(refbilltype)不可为空!");
			AssertUtils.isNotBlank(refbillid, "关联业务单id(refbillid)不可为空!");
			AssertUtils.isNotBlank(refbillcode, "关联业务单编码(refbillcode)不可为空!");
			AssertUtils.notNull(totpcs, "总件数(totpcs)不可为空!");
			AssertUtils.isNotBlank(createby, "录入员(createby)不可为空!");
			AssertUtils.notNull(createdate, "录入时间(createdate)不可为空!");
		} else {
			AssertUtils.isNotBlank(billid, "异常收货单id(billid)不可为空!");
		}
		// 校验所有明细总量是否超收(移动到明细处理,处理每一条明细)
	}

	@Override
	@Transactional
	public Object delWithRelated(RcvErrorQueryVO queryVO) {
		List<InReceivingAbnormalH> findAll = this.findAll(queryVO);
		if (!ObjectUtils.isEmpty(findAll)) {
			List<String> collect = findAll.stream().filter(p -> !StringUtils.isBlank(p.getBillid()))
					.map(InReceivingAbnormalH::getBillid).collect(Collectors.toList());

			Criteria crt = Criteria.forClass(InReceivingAbnormalD.class);
			Restriction in = Restrictions.in("billid", collect.toArray());
			crt.setRestriction(in);
			this.dMapper.deleteByCriteria(crt);

			this.hMapper.deleteById(collect, InReceivingAbnormalH.class);
		}
		return null;
	}

	@Override
	@Transactional
	public Object editWithRelated(RcvErrorDTO rcvErrorDTO) {
		InReceivingAbnormalH head = rcvErrorDTO.getHead();
		AssertUtils.notNull(head, "收货异常保存的头表不可为空!");
		List<InReceivingAbnormalD> detailList = rcvErrorDTO.getDetailList();
		AssertUtils.isNotEmpty(detailList, "收货异常保存的明细不可为空!");

		UserDTO userDTO = userUtils.getUserDTO();
		boolean editFlag = Boolean.TRUE;
		this.addHead(head, userDTO, editFlag);
		this.addDetails(head, detailList, userDTO, editFlag);
		return null;
	}

	@Override
	public Page<InReceivingAbnormalH> page(RcvErrorQueryVO queryVO) {
		AssertUtils.notNull(queryVO, "查询的条件不可为空!");
		Integer pageNum = queryVO.getPageNum();
		Integer pageSize = queryVO.getPageSize();
		if (ObjectUtils.isNull(pageNum)) {
			pageNum = 1;
		}
		if (ObjectUtils.isNull(pageSize)) {
			pageSize = 15;
		}
		PageUtils.startPage(pageNum, pageSize);
		return PageUtils.getPage(this.hMapper.findByCriteria(this.buildCriteria(queryVO)));
	}

	private Criteria buildCriteria(RcvErrorQueryVO queryVO) {
		Criteria crt = Criteria.forClass(InReceivingAbnormalH.class);
		Restriction condition = null;

		List<String> includeIds = queryVO.getIncludeIds();
		String billno = queryVO.getBillno();
		String billtype = queryVO.getBilltype();
		String branchid = queryVO.getBranchid();
		String consignorid = queryVO.getConsignorid();
		String refbillcode = queryVO.getRefbillcode();
		String status = queryVO.getStatus();
		String auditResult = queryVO.getAuditResult();
		String vendorname = queryVO.getVendorname();
		Date startDate = queryVO.getStartDate();
		Date endDate = queryVO.getEndDate();

		Restriction r0 = ObjectUtils.isEmpty(includeIds) ? null : Restrictions.in("billid", includeIds.toArray());
		Restriction r1 = StringUtils.isBlank(billno) ? null : Restrictions.likeAllIgnoreCase("billno", billno);
		Restriction r2 = StringUtils.isBlank(billtype) ? null : Restrictions.eq("billtype", billtype);
		Restriction r3 = StringUtils.isBlank(branchid) ? null : Restrictions.eq("branchid", branchid);
		Restriction r4 = StringUtils.isBlank(consignorid) ? null : Restrictions.eq("consignorid", consignorid);
		Restriction r5 = StringUtils.isBlank(refbillcode) ? null
				: Restrictions.likeAllIgnoreCase("refbillcode", refbillcode);
		Restriction r6 = StringUtils.isBlank(status) ? null : Restrictions.eq("status", status);
		Restriction r7 = StringUtils.isBlank(auditResult) ? null : Restrictions.eq("auditResult", auditResult);
		Restriction r8 = StringUtils.isBlank(vendorname) ? null
				: Restrictions.likeAllIgnoreCase("vendorname", vendorname);
		Restriction r9 = ObjectUtils.isNull(startDate) ? null : Restrictions.ge("createdate", startDate);
		Restriction r10 = ObjectUtils.isNull(endDate) ? null : Restrictions.le("createdate", endDate);

		condition = Restrictions.and(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10);
		crt.setRestriction(condition);
		crt.setOrder(Order.newInstance().asc("billid").desc("lastmodifydate"));
		return crt;
	}

	@Override
	public List<InReceivingAbnormalH> findAll(RcvErrorQueryVO queryVO) {
		AssertUtils.notNull(queryVO, "查询的条件不可为空!");
		return this.hMapper.findByCriteria(this.buildCriteria(queryVO));
	}

	@Override
	public RcvErrorDTO findOne(String id) {
		AssertUtils.isNotBlank(id, "查询的异常收货单主键id不可为空!");
		InReceivingAbnormalH findById = this.hMapper.findById(id, InReceivingAbnormalH.class);
		List<InReceivingAbnormalD> details = getDetails(id);
		RcvErrorDTO dto = new RcvErrorDTO();
		dto.setHead(findById);
		dto.setDetailList(details);
		return dto;
	}

	@Override
	public Object callToOms(RcvErrorQueryVO queryVO) {
		AssertUtils.notNull(queryVO, "查询的条件不可为空!");
		List<InReceivingAbnormalH> findAll = this.findAll(queryVO);
		if (!ObjectUtils.isEmpty(findAll)) {
			for (InReceivingAbnormalH inReceivingAbnormalH : findAll) {
				String status = inReceivingAbnormalH.getStatus();
				if (status.equals("10")) {
					continue;
				}
				String billid = inReceivingAbnormalH.getBillid();
				// 需要根据asnHeaderId获取所有收货单id
				EtlMessage em = new EtlMessage();
				em.setId(billid);
				em.setEtlType(EtlTypeConstants.in_re_abnormal_w2o);
				try {
					log.info("入库异常单回传给data-exchange数据:{}", JsonUtils.toString(em));
					exchangeSender.send(em);
					log.info("入库异常单回传给data-exchange成功!");
				} catch (Exception e) {
					log.error("入库异常单回传失败,原因->{}", e);
				}
			}
		}
		return null;
	}

	@Override
	public List<InReceivingAbnormalD> getDetails(String id) {
		AssertUtils.isNotBlank(id, "查询的异常收货单主键id不可为空!");
		return this.dMapper.findByMap(MapUtils.put("billid", id).getMap(), InReceivingAbnormalD.class);
	}

}
