package com.uas.platform.b2b.service.impl;

import com.uas.platform.b2b.core.util.ContextUtils;
import com.uas.platform.b2b.core.util.ThreadTask;
import com.uas.platform.b2b.dao.*;
import com.uas.platform.b2b.erp.model.PurchaseNotify;
import com.uas.platform.b2b.event.PurchaseNoticeEndReleaseEvent;
import com.uas.platform.b2b.event.PurchaseNoticeSaveReleaseEvent;
import com.uas.platform.b2b.event.SaleSendAcceptReleaseEvent;
import com.uas.platform.b2b.event.SaleSendRefuseReleaseEvent;
import com.uas.platform.b2b.model.*;
import com.uas.platform.b2b.search.SearchService;
import com.uas.platform.b2b.service.PurchaseNoticeService;
import com.uas.platform.b2b.support.SystemSession;
import com.uas.platform.b2b.support.XingePusher;
import com.uas.platform.core.model.Constant;
import com.uas.platform.core.model.PageInfo;
import com.uas.platform.core.model.Status;
import com.uas.platform.core.persistence.criteria.PredicateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

@Service
public class PurchaseNoticeServiceImpl implements PurchaseNoticeService {

	@Autowired
	private PurchaseNoticeDao purchaseNoticeDao;

	@Autowired
	private SaleSendDao saleSendDao;

	@Autowired
	private SaleSendItemDao saleSendItemDao;

	@Autowired
	private SaleSendItemVerifyDao saleSendItemVerifyDao;

	@Autowired
	private UserBaseInfoDao userBaseInfoDao;

	@Autowired
	private SearchService searchService;

	@Autowired
	private DistributeDao distributeDao;

	@Autowired
	private  RoleDao roleDao;

	@Autowired
	private  UserOrderDao userOrderDao;

	@Autowired
	private  UserDao userDao;

	@Autowired
	private VendorDao vendorDao;

	@Override
	public List<PurchaseNotice> save(List<PurchaseNotice> notices) {
		notices = purchaseNoticeDao.save(notices);
		saveUserOrders(notices);
		ContextUtils.publishEvent(new PurchaseNoticeSaveReleaseEvent(notices));
		return notices;
	}

	private void saveUserOrders(final List<PurchaseNotice> notices) {

		ThreadTask.getInstance().execute(new Runnable() {
			@Override
			public void run() {
                /* 添加供应商的阅读记录*/
				for(PurchaseNotice notice : notices) {
					Set<Long> userUUs = new HashSet<>();
					// 添加管理员
					List<Role> roles = roleDao.findByEnUUAndIssys(notice.getVendUU(), Constant.YES);
					if (!CollectionUtils.isEmpty(roles)) {
						List<User> admins = userDao.findByRole(roles.get(0).getId());
						for (User admin : admins) {
							if (!userUUs.contains(admin.getUserUU())) {
								userUUs.add(admin.getUserUU());
							}
						}
					}
					List<Vendor> vendors = vendorDao.findByMyEnUUAndVendUU(notice.getEnUU(), notice.getVendUU());
					// 查找有权限的用户
					if (!CollectionUtils.isEmpty(vendors)) {
						Long vendorId = vendors.get(0).getId();
						List<Distribute> distributes = distributeDao.findByVendorId(vendorId);
						if (!CollectionUtils.isEmpty(distributes)) {
							for (Distribute distribute : distributes) {
								if (!userUUs.contains(distribute.getUserUU())) {
									userUUs.add(distribute.getUserUU());
								}
							}
						}
					}
					UserOrders userOrders;
					List<UserOrders> list = new ArrayList<>();
					for (Long userUU : userUUs) {
						if (userUU == null) {
							continue;
						}
						userOrders = new UserOrders(userUU, notice.getVendUU(), notice.getId(), "sale", "purc$notice");
						list.add(userOrders);
					}

                    /* 添加采购员的阅读记录*/
                    if (notice.getOrderItem().getOrder().getUserUU() != null) {
                        userOrders = new UserOrders(notice.getOrderItem().getOrder().getUserUU(), notice.getEnUU(), notice.getId(), "purc", "purc$notice");
						userOrders.setReadStatus((short) Status.READ.value());
                        list.add(userOrders);
                    }
					userOrderDao.save(list);
				}
			}
		});
	}

	@Override
	public Page<PurchaseNotice> findAllByPageInfo(final PageInfo pageInfo, final String keyword, final Long fromDate,
			final Long endDate, final SearchFilter filter) {
		return purchaseNoticeDao.findAll(new Specification<PurchaseNotice>() {
			@Override
			public Predicate toPredicate(Root<PurchaseNotice> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
				if (filter != null) {
					if (!CollectionUtils.isEmpty(filter.getDistribute())) {
						pageInfo.expression(PredicateUtils.in("enUU", filter.getDistribute(), false));
					}
				}
				if (StringUtils.hasText(keyword)) {
					List<Object> lists = new ArrayList<>();
					List<PurchaseNotice> listss = searchService.searchPurchaseNoticeIds(keyword, null).getContent();
					for (PurchaseNotice list : listss) {
						lists.add(list.getId());
					}
					pageInfo.expression(PredicateUtils.in("id", lists, false));
				}
				if (fromDate != null) {
					pageInfo.expression(PredicateUtils.in("id", purchaseNoticeDao.findByFromDate(
							SystemSession.getUser().getEnterprise().getUu(), new Date(fromDate)), false));
				}
				if (endDate != null) {
					pageInfo.expression(PredicateUtils.in("id", purchaseNoticeDao
							.findByEndDate(SystemSession.getUser().getEnterprise().getUu(), new Date(endDate)), false));
				}
				return query.where(pageInfo.getPredicates(root, query, builder)).getRestriction();
			}
		}, pageInfo);
	}

    @Override
	public Page<PurchaseNotice> findDoneByPageInfo(final PageInfo pageInfo, final String keyword, final Long fromDate,
			final Long endDate) {
		return purchaseNoticeDao.findAll(new Specification<PurchaseNotice>() {
			@Override
			public Predicate toPredicate(Root<PurchaseNotice> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
				pageInfo.filter("status", Status.REPLIED.value());
				pageInfo.expression(
						PredicateUtils.or(PredicateUtils.isNull("end"), PredicateUtils.ne("end", Constant.YES, false)));
				if (StringUtils.hasText(keyword)) {
					List<Object> lists = new ArrayList<>();
					List<PurchaseNotice> listss = searchService.searchPurchaseNoticeIds(keyword, null).getContent();
					for (PurchaseNotice list : listss) {
						lists.add(list.getId());
					}
					pageInfo.expression(PredicateUtils.in("id", lists, false));
				}
				if (fromDate != null) {
					pageInfo.expression(PredicateUtils.in("id", purchaseNoticeDao.findByFromDate(
							SystemSession.getUser().getEnterprise().getUu(), new Date(fromDate)), false));
				}
				if (endDate != null) {
					pageInfo.expression(PredicateUtils.in("id", purchaseNoticeDao
							.findByEndDate(SystemSession.getUser().getEnterprise().getUu(), new Date(endDate)), false));
				}
				return query.where(pageInfo.getPredicates(root, query, builder)).getRestriction();
			}
		}, pageInfo);
	}

	@Override
	public PurchaseNotice findById(Long id) {
		return purchaseNoticeDao.findOne(id);
	}

	@Override
	public void send(List<SaleSendItem> sendItems) {
		saleSendItemDao.save(sendItems);
		for (SaleSendItem item : sendItems) {
			if (item.getNoticeId() != null) {
				purchaseNoticeDao.updateBySend(item.getNoticeId());
				// 更新发货状态
				updateNoticeStatus(item.getNoticeId());
			}
		}
	}

	@Override
	public List<PurchaseNotice> findNotUploadNotice() {
		return purchaseNoticeDao.findByVendUUAndSendStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public void onNoticeDownSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseNotice notice = purchaseNoticeDao.findOne(Long.parseLong(id));
			if (notice != null) {
				notice.setSendStatus((short) Status.DOWNLOADED.value());
				purchaseNoticeDao.save(notice);
			}
		}
	}

	@Override
	public List<SaleSend> findNotUploadSend() {
		return saleSendDao.findByCustUUAndSendStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public List<SaleSend> findNotUploadSendEDI(Long enUU) {
		return saleSendDao.findByCustUUAndSendStatus(enUU,
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public List<SaleSend> findNotSendSend() {
		return saleSendDao.findByEnUUAndBackStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public void onSendUploadSuccess(String[] idArray) {
		for (String id : idArray) {
			SaleSend send = saleSendDao.findOne(Long.parseLong(id));
			if (send != null) {
				send.setSendStatus((short) Status.DOWNLOADED.value());
				saleSendDao.save(send);
			}
		}
	}

	@Override
	public void onSendDownSuccess(String[] idArray) {
		for (String id : idArray) {
			SaleSend send = saleSendDao.findOne(Long.parseLong(id));
			if (send != null) {
				send.setBackStatus((short) Status.DOWNLOADED.value());
				saleSendDao.save(send);
			}
		}
	}

	@Override
	public void end(List<PurchaseNotify> notifies) {
		long enUU = SystemSession.getUser().getEnterprise().getUu();
		List<PurchaseNotice> saveList = new ArrayList<>();
		for (PurchaseNotify notify : notifies) {
			List<PurchaseNotice> notices = purchaseNoticeDao.findByEnUUAndSourceId(enUU, notify.getPn_id());
			if (!CollectionUtils.isEmpty(notices)) {
				PurchaseNotice notice = notices.get(0);
				notice.setEnd(Constant.YES);
				notice.setEndStatus((short) Status.NOT_UPLOAD.value());
				notice.setErpDate(new Date(System.currentTimeMillis()));
				saveList.add(notice);
				// 推送结案送回提醒给采购单供应商联系人
				Long vendUserUU = notice.getOrderItem().getOrder().getVendUserUU();
				if (vendUserUU != null) {
					UserBaseInfo user = userBaseInfoDao.findOne(vendUserUU);
					XingePusher.pushByUser(user, "客户取消了送货提醒", "物料:" + notice.getOrderItem().getProduct().getTitle(), "",
							"");
				}
			}
		}
        purchaseNoticeDao.save(saveList);
		ContextUtils.publishEvent(new PurchaseNoticeEndReleaseEvent(saveList));
	}

	@Override
	public List<PurchaseNotice> findNotSendEnd() {
		return purchaseNoticeDao.findByVendUUAndEndStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public void onEndDownSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseNotice notice = purchaseNoticeDao.findOne(Long.parseLong(id));
			if (notice != null) {
				notice.setEndStatus((short) Status.DOWNLOADED.value());
				purchaseNoticeDao.save(notice);
			}
		}
	}

	@Override
	public void onSaleSendChange(List<SaleSendItem> sendItems) {
		List<Long> ids = new ArrayList<>();
		for (SaleSendItem item : sendItems) {
			saleSendItemDao.updateByReply(item.getId(), item.getQty(), item.getReplyRemark());
			if (item.getNoticeId() != null) {
				purchaseNoticeDao.updateBySend(item.getNoticeId());
                updateNoticeStatus(item.getNoticeId());
				ids.add(item.getNoticeId());
			}
		}
		// 买家拒收之后给卖家发消息
		ContextUtils.publishEvent(new SaleSendRefuseReleaseEvent(SaleSendItem.distinct(sendItems)));
	}

    /**
     * 更新发货提醒状态
     *
     * @param noticeId 发货提醒id
     */
    private void updateNoticeStatus(Long noticeId) {
        PurchaseNotice notice = purchaseNoticeDao.findOne(noticeId);
        if (notice.getEndQty() < notice.getQty() && notice.getStatus() == Status.REPLIED.value()) {
            purchaseNoticeDao.updateStatus(notice.getId(), (short) Status.NOT_REPLY.value());
        }
    }

    @Override
	public List<PurchaseNotice> findById(Long[] ids) {
		return purchaseNoticeDao.findUnEndByIds(ids);
	}

	@Override
	public void onVerify(List<SaleSendItemVerify> verifies) {
		verifies = saleSendItemVerifyDao.save(verifies);
		List<SaleSendItem> saleSendItems = new ArrayList<>();
		for (SaleSendItemVerify verify : verifies) {
			saleSendItemDao.updateByVerify(verify.getSendItemId());
			updateVerifyStatus(verify.getSendItemId());
			SaleSendItem item = saleSendItemDao.findOne(verify.getSendItemId());
			saleSendItems.add(item);
		}
		// 买家收料之后给卖家发消息
		ContextUtils.publishEvent(new SaleSendAcceptReleaseEvent(SaleSendItem.distinct(saleSendItems)));
	}

	@Override
	public void unVerify(List<SaleSendItemVerify> verifies) {
		saleSendItemVerifyDao.delete(verifies);
		for (SaleSendItemVerify verify : verifies) {
			saleSendItemDao.updateByVerify(verify.getSendItemId());
			updateVerifyStatus(verify.getSendItemId());
		}
	}

	/**
	 * 更新发货单的收料状态
	 * 
	 * @param sendItemId
	 */
	private void updateVerifyStatus(Long sendItemId) {
		SaleSendItem sendItem = saleSendItemDao.findOne(sendItemId);
		int totalCount = saleSendItemDao.getTotalCountBySendId(sendItem.getSend().getId());
		int verifyCount = saleSendItemDao.getFullVerifyCountBySendId(sendItem.getSend().getId());
		if (verifyCount == totalCount) {
			sendItem.getSend().setVerifystatus(Constant.YES);
		} else {
			sendItem.getSend().setVerifystatus(Constant.NO);
		}
		saleSendItemDao.save(sendItem);
	}

}
