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.event.PurchaseProofingApprovalSaveReleaseEvent;
import com.uas.platform.b2b.event.PurchaseProofingItemSaveReleaseEvent;
import com.uas.platform.b2b.model.*;
import com.uas.platform.b2b.search.SearchService;
import com.uas.platform.b2b.service.PurchaseProofingService;
import com.uas.platform.b2b.support.SPageUtils;
import com.uas.platform.b2b.support.SystemSession;
import com.uas.platform.b2b.support.XingePusher;
import com.uas.platform.core.exception.IllegalOperatorException;
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 com.uas.search.b2b.model.PageParams;
import com.uas.search.b2b.model.SPage;
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.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
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.*;

@SuppressWarnings("deprecation")
@Service
public class PurchaseProofingServiceImpl implements PurchaseProofingService {

	@Autowired
	private PurchaseProofingItemDao purchaseProofingItemDao;

	@Autowired
	private PurchaseProofingItemDoneDao purchaseProofingItemDoneDao;

	@Autowired
	private PurchaseProofingItemTodoDao purchaseProofingItemTodoDao;

	@Autowired
	private PurchaseProofingDao purchaseProofingDao;

	@Autowired
	private PurchaseProofingSendDao purchaseProofingSendDao;

	@Autowired
	private PurchaseProofingApprovalDao purchaseProofingApprovalDao;

	@Autowired
	private AttachDao attachDao;

	@Autowired
	private UserBaseInfoDao userBaseInfoDao;

	@Autowired
	private SearchService searchService;

	@Autowired
	private RoleDao roleDao;

	@Autowired
	private UserDao userDao;

	@Autowired
	private VendorDao vendorDao;

	@Autowired
	private DistributeDao distributeDao;

	@Autowired
	private UserOrderDao userOrderDao;

	@Override
    public void save(List<PurchaseProofingItem> proofingItems) {
		proofingItems = purchaseProofingItemDao.save(proofingItems);
		saveUserOrders(proofingItems);
		// 保存时产生消息
		ContextUtils.publishEvent(new PurchaseProofingItemSaveReleaseEvent(proofingItems));
	}

	private void saveUserOrders(final List<PurchaseProofingItem> proofingItems) {

		ThreadTask.getInstance().execute(new Runnable() {
			@Override
			public void run() {
            	/* 添加供应商的阅读记录*/
				for(PurchaseProofingItem item : proofingItems) {
					Set<Long> userUUs = new HashSet<>();
					// 添加管理员
					List<Role> roles = roleDao.findByEnUUAndIssys(item.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(item.getProofing().getEnUU(), item.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, item.getVendUU(), item.getId(), "sale", "purc$proofingitems");
						list.add(userOrders);
					}

                	/* 添加采购员的阅读记录*/
					if (item.getProofing().getUserUU() != null) {
						userOrders = new UserOrders(item.getProofing().getUserUU(), item.getProofing().getEnUU(), item.getId(), "purc", "purc$proofingitems");
						list.add(userOrders);
					}
					userOrderDao.save(list);
				}
			}
		});

	}

	@Override
	public void saveAttach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofing> proofings = purchaseProofingDao.findByEnUUAndCode(enUU, attach.getSourceId());
				if (!CollectionUtils.isEmpty(proofings)) {
					PurchaseProofing proofing = proofings.get(0);
					attach.setRelativeTable("purc$proofing");
					attach.setRelativeKey(proofing.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
            attachDao.save(validAttachs);
        }
	}


	@Override
	public void saveSendAttach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofingSend> proofingSends = purchaseProofingSendDao.findByProofingItemVendUUAndCode(enUU,
						attach.getSourceId());
				if (!CollectionUtils.isEmpty(proofingSends)) {
					PurchaseProofingSend proofingSend = proofingSends.get(0);
					attach.setRelativeTable("purc$proofingsend");
					attach.setRelativeKey(proofingSend.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
            attachDao.save(validAttachs);
        }
	}

	@Override
	public void saveApprovalAttach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofingApproval> approvals = purchaseProofingApprovalDao.findByEnUUAndCode(enUU,
						attach.getSourceId());
				if (!CollectionUtils.isEmpty(approvals)) {
					PurchaseProofingApproval approval = approvals.get(0);
					attach.setRelativeTable("purc$proofingapproval");
					attach.setRelativeKey(approval.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
			attachDao.save(validAttachs);
		}
	}

	@Override
	public void saveApprovalPrdattach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofingApproval> approvals = purchaseProofingApprovalDao.findByEnUUAndCode(enUU,
						attach.getSourceId());
				if (!CollectionUtils.isEmpty(approvals)) {
					PurchaseProofingApproval approval = approvals.get(0);
					attach.setRelativeTable("purc$proofingapproval_prd");
					attach.setRelativeKey(approval.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
			attachDao.save(validAttachs);
		}
	}

	@Override
	public void saveApprovalPadattach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofingApproval> approvals = purchaseProofingApprovalDao.findByEnUUAndCode(enUU,
						attach.getSourceId());
				if (!CollectionUtils.isEmpty(approvals)) {
					PurchaseProofingApproval approval = approvals.get(0);
					attach.setRelativeTable("purc$proofingapproval_pad");
					attach.setRelativeKey(approval.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
			attachDao.save(validAttachs);
		}
	}

	@Override
	public void saveApprovalPpdattach(List<Attach> attachs) {
		List<Attach> validAttachs = new ArrayList<Attach>();
		if (!CollectionUtils.isEmpty(attachs)) {
			long enUU = SystemSession.getUser().getEnterprise().getUu();
			for (Attach attach : attachs) {
				List<PurchaseProofingApproval> approvals = purchaseProofingApprovalDao.findByEnUUAndCode(enUU,
						attach.getSourceId());
				if (!CollectionUtils.isEmpty(approvals)) {
					PurchaseProofingApproval approval = approvals.get(0);
					attach.setRelativeTable("purc$proofingapproval_ppd");
					attach.setRelativeKey(approval.getId());
					validAttachs.add(attach);
				}
			}
		}
		if (!CollectionUtils.isEmpty(validAttachs)) {
			attachDao.save(validAttachs);
		}
	}

	@Override
	public List<PurchaseProofingItem> findNotUploadProofing() {
		return purchaseProofingItemDao.findByVendUUAndSendStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public void uploadProofingSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseProofingItem proofingItem = purchaseProofingItemDao.findOne(Long.parseLong(id));
			if (proofingItem != null) {
				proofingItem.setSendStatus((short) Status.DOWNLOADED.value());
				purchaseProofingItemDao.save(proofingItem);
			}
		}
	}

	@Override
	public Page<PurchaseProofingItem> findAllByPageInfo(final PageInfo pageInfo, final String keyword,
			final SearchFilter filter) {
		return purchaseProofingItemDao.findAll(new Specification<PurchaseProofingItem>() {

			@Override
            public Predicate toPredicate(Root<PurchaseProofingItem> root, CriteriaQuery<?> query,
                                         CriteriaBuilder builder) {
				if (filter != null) {
					if (!CollectionUtils.isEmpty(filter.getDistribute())) {
                        pageInfo.expression(PredicateUtils.in("proofing.enUU", filter.getDistribute(), false));
                    }
					if (filter.getFromDate() != null) {
                        pageInfo.expression(PredicateUtils.gte("date", new Date(filter.getFromDate()), false));
                    }
					if (filter.getEndDate() != null) {
                        pageInfo.expression(PredicateUtils.lte("date", new Date(filter.getEndDate()), false));
                    }
				}
				if (StringUtils.hasText(keyword)) {
					List<Object> lists = new ArrayList<>();
					PageParams pageParams = new PageParams();
					ModelMap map = new ModelMap();
					map.put("ppi_venduu", SystemSession.getUser().getEnterprise().getUu());
					pageParams.setFilters(map);
					for (PurchaseProofingItem list : searchService.searchPurchaseProofingItemIds(keyword, pageParams)
							.getContent()) {
						lists.add(list.getId());
					}
					pageInfo.expression(PredicateUtils.in("id", lists, false));
				}
				query.where(pageInfo.getPredicates(root, query, builder));
				return null;
			}
		}, pageInfo);
	}

	@Override
	public SPage<PurchaseProofingItem> findByPageInfo(PageInfo pageInfo, String keyword, SearchFilter filter) {
		return SPageUtils.covertSPage(findAllByPageInfo(pageInfo, keyword, filter));
	}

	@Override
	public PurchaseProofingItem findById(Long id) {
		return purchaseProofingItemDao.findOne(id);
	}

	@Override
	public PurchaseProofingSend send(PurchaseProofingSend proofingSend) {
		return send(proofingSend, true);
	}

	@Override
	@Transactional
	public void send(List<PurchaseProofingSend> proofingSend) {
		for (PurchaseProofingSend send : proofingSend) {
			send(send, false);
		}
	}

	public PurchaseProofingSend send(PurchaseProofingSend proofingSend, boolean isB2b) {
		if (isB2b) {// 平台上的操作
			proofingSend.setDate(new Date());
			// 设置传输到买方ERP的状态为未上传
			proofingSend.setSendStatus((short) Status.NOT_UPLOAD.value());
			// 设置传输到卖方ERP的状态为未上传
			proofingSend.setBackStatus((short) Status.NOT_UPLOAD.value());
			proofingSend.setRecorder(SystemSession.getUser().getUserName());
		} // 从卖方ERP传输过来的单据在类型转换时设置好了状态，所以此处不需要设置
		PurchaseProofingItem proofingItem = purchaseProofingItemDao.findOne(proofingSend.getProofingItem().getId());
		if (proofingItem == null) {
			throw new IllegalOperatorException("不存在的客户打样申请");
		}
		if (proofingSend.getCode() == null) {
			throw new IllegalOperatorException("送样单号不能为空");
		} else {
			List<PurchaseProofingSend> proofingSends = purchaseProofingSendDao.findByProofingItemVendUUAndCode(
					SystemSession.getUser().getEnterprise().getUu(), proofingSend.getCode());
			if (proofingSends.size() > 0) {
				if (isB2b)// b2B上操作,报错
                {
                    throw new IllegalOperatorException("送样单号已存在");
                } else
					// 卖方ERP的操作数据上传过来,忽略
                {
                    return null;
                }
			}
		}
		if (null != proofingItem.getSendQty()) { // proofingItem中的sendQty用来判断是否完成送样
			proofingItem.setSendQty(proofingSend.getSendQty() + proofingItem.getSendQty());
		} else {
			proofingItem.setSendQty(proofingSend.getSendQty());
		}
		proofingItem.setStatus((short) Status.SEND.value());
		proofingSend.setProofingItem(proofingItem);
		proofingSend = purchaseProofingSendDao.save(proofingSend);
		purchaseProofingItemDao.save(proofingItem);
		if (proofingItem.getProofing().getUserUU() != null) {
			UserBaseInfo user = userBaseInfoDao.findOne(proofingItem.getProofing().getUserUU());
			XingePusher.pushByUser(user, "供应商给您送样了", "供应商：" + SystemSession.getUser().getEnterprise().getEnName(), "",
					"");
		}
		return proofingSend;
	}

	@Override
	public List<PurchaseProofingSend> findNotBackSampleSend() {
		return purchaseProofingSendDao.findByBackStatusAndProofingItemVendUU((short) Status.NOT_UPLOAD.value(),
				SystemSession.getUser().getEnterprise().getUu());
	}

	@Override
	public void backSampleSendSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseProofingSend proofingSend = purchaseProofingSendDao.findOne(Long.parseLong(id));
			if (proofingSend != null) {
				proofingSend.setBackStatus((short) Status.DOWNLOADED.value());
				purchaseProofingSendDao.save(proofingSend);
			}
		}
	}

	@Override
	public List<PurchaseProofingSend> findNotSendSampleSend() {
		return purchaseProofingSendDao.findBySendStatusAndProofingItemProofingEnUU((short) Status.NOT_UPLOAD.value(),
				SystemSession.getUser().getEnterprise().getUu());
	}

	@Override
	public void sendSampleSendSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseProofingSend proofingSend = purchaseProofingSendDao.findOne(Long.parseLong(id));
			if (proofingSend != null) {
				proofingSend.setSendStatus((short) Status.DOWNLOADED.value());
				purchaseProofingSendDao.save(proofingSend);
			}
		}
	}

	@Override
	public void saveSampleApproval(List<PurchaseProofingApproval> proofingApprovals) {
		purchaseProofingApprovalDao.save(proofingApprovals);
		// 消息事件
		ContextUtils.publishEvent(new PurchaseProofingApprovalSaveReleaseEvent(proofingApprovals));
	}

	@Override
	public List<PurchaseProofingApproval> findNotUploadApprovals() {
		return purchaseProofingApprovalDao.findByVendUUAndSendStatus(SystemSession.getUser().getEnterprise().getUu(),
				(short) Status.NOT_UPLOAD.value());
	}

	@Override
	public void uploadApprovalsSuccess(String[] idArray) {
		for (String id : idArray) {
			PurchaseProofingApproval approval = purchaseProofingApprovalDao.findOne(Long.parseLong(id));
			if (approval != null) {
				approval.setSendStatus((short) Status.DOWNLOADED.value());
				purchaseProofingApprovalDao.save(approval);
			}
		}
	}

	@Override
	public Page<PurchaseProofingItemTodo> findTodoByPageInfo(final PageInfo pageInfo, final String keyword,
			final SearchFilter filter) {
		if (filter != null) {
			if (!CollectionUtils.isEmpty(filter.getDistribute())) {
                pageInfo.expression(PredicateUtils.in("proofing.enUU", filter.getDistribute(), false));
            }
			if (filter.getFromDate() != null) {
                pageInfo.expression(PredicateUtils.gte("date", new Date(filter.getFromDate()), false));
            }
			if (filter.getEndDate() != null) {
                pageInfo.expression(PredicateUtils.lte("date", new Date(filter.getEndDate()), false));
            }
		}
		if (StringUtils.hasText(keyword)) {
			List<Object> lists = new ArrayList<>();
			PageParams pageParams = new PageParams();
			ModelMap map = new ModelMap();
			map.put("ppi_venduu", SystemSession.getUser().getEnterprise().getUu());
			pageParams.setFilters(map);
			for (PurchaseProofingItem list : searchService.searchPurchaseProofingItemIds(keyword, pageParams)
					.getContent()) {
				lists.add(list.getId());
			}
			pageInfo.expression(PredicateUtils.in("id", lists, false));
		}
		return purchaseProofingItemTodoDao.findAll(new Specification<PurchaseProofingItemTodo>() {
			@Override
            public Predicate toPredicate(Root<PurchaseProofingItemTodo> root, CriteriaQuery<?> query,
                                         CriteriaBuilder builder) {
				return query.where(pageInfo.getPredicates(root, query, builder)).getRestriction();
			}
		}, pageInfo);
	}

	@Override
	public Page<PurchaseProofingItemDone> findDoneByPageInfo(final PageInfo pageInfo, final String keyword,
			final SearchFilter filter) {
		if (filter != null) {
			if (!CollectionUtils.isEmpty(filter.getDistribute())) {
                pageInfo.expression(PredicateUtils.in("proofing.enUU", filter.getDistribute(), false));
            }
			if (filter.getFromDate() != null) {
                pageInfo.expression(PredicateUtils.gte("date", new Date(filter.getFromDate()), false));
            }
			if (filter.getEndDate() != null) {
                pageInfo.expression(PredicateUtils.lte("date", new Date(filter.getEndDate()), false));
            }
		}
		if (StringUtils.hasText(keyword)) {
			List<Object> lists = new ArrayList<>();
			PageParams pageParams = new PageParams();
			ModelMap map = new ModelMap();
			map.put("ppi_venduu", SystemSession.getUser().getEnterprise().getUu());
			pageParams.setFilters(map);
			for (PurchaseProofingItem list : searchService.searchPurchaseProofingItemIds(keyword, pageParams)
					.getContent()) {
				lists.add(list.getId());
			}
			pageInfo.expression(PredicateUtils.in("id", lists, false));
		}
		return purchaseProofingItemDoneDao.findAll(new Specification<PurchaseProofingItemDone>() {
			@Override
            public Predicate toPredicate(Root<PurchaseProofingItemDone> root, CriteriaQuery<?> query,
                                         CriteriaBuilder builder) {
				return query.where(pageInfo.getPredicates(root, query, builder)).getRestriction();
			}
		}, pageInfo);
	}

	@Override
	public void print(Long id) {
		PurchaseProofingItem proofingItem = purchaseProofingItemDao.findOne(id);
		if (proofingItem != null) {
			proofingItem.setPrint((short) ((proofingItem.getPrint() == null ? 0 : proofingItem.getPrint()) + 1));
		}
		purchaseProofingItemDao.save(proofingItem);
	}

    @Override
    public void invalidateProductSample(String[] ids) {
		List<PurchaseProofingItem> saveItems = new ArrayList<>();
		for (String id : ids) { // erp单据id
			List<PurchaseProofing> proofingList = purchaseProofingDao.findByErpId(Long.parseLong(id));
			if (!CollectionUtils.isEmpty(proofingList)) {
				PurchaseProofing proofing = proofingList.get(0);
				for (PurchaseProofingItem proofingItem : proofing.getProofingItems()) {
					proofingItem.setStatus((short)Status.CANCELLED.value());
					saveItems.add(proofingItem);
				}
			}
		}
		purchaseProofingItemDao.save(saveItems);
    }
}
