package com.cku.oa.sampling.service;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.cku.core.ZAErrorCode;
import com.cku.core.ZAException;
import com.cku.oa.dog.dao.DogBirthCertificateDao;
import com.cku.oa.dog.dao.DogPedigreeCertifiedChangeDao;
import com.cku.oa.dog.entity.Dog;
import com.cku.oa.dog.entity.DogBirthCertificate;
import com.cku.oa.dog.entity.DogChip;
import com.cku.oa.dog.entity.DogPedigreeCertifiedChange;
import com.cku.oa.dog.service.DogChipService;
import com.cku.oa.dog.service.DogService;
import com.cku.oa.sampling.dao.SamplingDao;
import com.cku.oa.sampling.entity.Sampling;
import com.cku.oa.sampling.entity.SamplingFlowLog;
import com.cku.oa.sampling.enums.SamplingDistributionChannelEnum;
import com.cku.oa.sampling.enums.SamplingDogSourceTypeEnum;
import com.cku.oa.sampling.enums.SamplingFlowStateEnum;
import com.cku.oa.sampling.enums.SamplingLogFlowTypeEnum;
import com.cku.oa.sampling.vo.SamplingDogExportVo;
import com.cku.oa.sampling.vo.SamplingExportVo;
import com.cku.oa.sampling.vo.SamplingImportVo;
import com.cku.oa.sys.entity.Org;
import com.cku.oa.sys.entity.user.IEnum;
import com.cku.oa.sys.entity.user.Member;
import com.cku.oa.sys.service.OrgService;
import com.cku.oa.sys.service.user.MemberService;
import com.cku.restful.v1.sys.utils.BeanUtil;
import com.cku.util.DateUtils;
import com.google.common.collect.Lists;
import com.thinkgem.jeesite.common.persistence.BaseEntity;
import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.service.CrudService;
import com.thinkgem.jeesite.common.utils.excel.ExportExcel;
import com.thinkgem.jeesite.common.utils.excel.ImportExcel;
import com.thinkgem.jeesite.modules.sys.entity.User;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;

/**
 * 采样包Service
 *
 * @author yuanshuai
 * @version 2023-05-22
 */

@Service
@Transactional(readOnly = true)
public class SamplingService extends CrudService<SamplingDao, Sampling> {

	@Autowired
	private SamplingFlowLogService samplingFlowLogService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private OrgService orgService;
	@Lazy
	@Autowired
	private DogService dogService;
	@Lazy
	@Autowired
	private DogChipService dogChipService;
	@Autowired
	private DogBirthCertificateDao dogBirthCertificateDao;
	@Autowired
	private DogPedigreeCertifiedChangeDao dogPedigreeCertifiedChangeDao;

	public Sampling get(String id) {
		return super.get(id);
	}

	/**
	 * 根据采样包编号查询
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 16:37
	 */
	public Sampling findBySamplingCode(String samplingCode) {
		if (StringUtils.isBlank(samplingCode)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号为空");
		}
		return dao.findBySamplingCode(samplingCode);
	}

	/**
	 * 根据采样包编号查询-区分大小写
	 *
	 * @author yuanshuai
	 * @date 2023/8/7 17:07
	 */
	public Sampling findBySamplingCodeWithCase(String samplingCode) {
		if (StringUtils.isBlank(samplingCode)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号为空");
		}
		return dao.findBySamplingCodeWithCase(samplingCode);
	}


	public List<Sampling> findList(Sampling sampling) {
		return super.findList(sampling);
	}

	public Page<Sampling> findPage(Page<Sampling> page, Sampling sampling) {
		//更换状态入参
		if (Objects.nonNull(sampling.getFlowState())
				&& (0 == sampling.getFlowState() || 1 == sampling.getFlowState())) {
			sampling.setBindType(sampling.getFlowState());
			sampling.setFlowState(null);
		}
		Page<Sampling> resultPage = super.findPage(page, sampling);
		//回显状态入参
		if (Objects.nonNull(sampling.getBindType())) {
			sampling.setFlowState(sampling.getBindType());
		}
		return resultPage;

	}

	/**
	 * 根据采样包编号查数量
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:26
	 */
	public Integer findCountBySamplingCode(String samplingCode) {
		if (StringUtils.isBlank(samplingCode)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号为空");
		}
		return dao.findCountBySamplingCode(samplingCode);
	}

	/**
	 * 根据会员号采样包列表
	 *
	 * @author yuanshuai
	 * @date 2023/5/28 13:11
	 */
	public List<Sampling> findListByMemberCode(String memberCode) {
		if (StringUtils.isBlank(memberCode)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "会员编号为空");
		}
		return dao.findListByMemberCode(memberCode);
	}

	/**
	 * 根据犬只编号查询采样包绑定记录
	 *
	 * @author zhangjunwu
	 * @date 2023/6/28 13:11
	 */
	public List<Sampling> findBindRecordByDogCodes(List<String> dogCodes) {
		if (CollectionUtils.isEmpty(dogCodes)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "犬只编号为空");
		}
		return dao.findBindRecordByDogCodes(dogCodes);
	}

	/**
	 * 根据ID列表查采样包列表
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:26
	 */
	public List<Sampling> findListByIdList(List<String> idList) {
		if (CollectionUtils.isEmpty(idList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "ID列表为空");
		}
		return dao.findListByIdList(idList);
	}

	/**
	 * 查询未使用采样包列表
	 *
	 * @author yuanshuai
	 * @date 2023/5/28 12:41
	 */
	public List<Sampling> findUnuseList() {
		return dao.findUnuseList();
	}

	/**
	 * 查找已绑定且没有dogId的采样包列表
	 *
	 * @author yuanshuai
	 * @date 2023/7/26 17:57
	 */
	public List<Sampling> findBindNoDogIdList() {
		return dao.findBindNoDogIdList();
	}

	/**
	 * 根据采样包编号列表查采样包列表
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:26
	 */
	public List<Sampling> findListBySamplingCodeList(List<String> samplingCodeList) {
		if (CollectionUtils.isEmpty(samplingCodeList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号列表为空");
		}
		return dao.findListBySamplingCodeList(samplingCodeList);
	}

	/**
	 * 批量添加
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 16:38
	 */
	private void batchInsert(List<Sampling> samplingList) {
		if (CollectionUtils.isEmpty(samplingList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包数据为空");
		}
		dao.batchInsert(samplingList);
	}

	/**
	 * 添加采样包
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:27
	 */
	@Transactional(readOnly = false)
	public void add(Sampling sampling) {
		if (StringUtils.isBlank(sampling.getSamplingCode())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号为空");
		}
		if (findCountBySamplingCode(sampling.getSamplingCode()) > 0) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号已存在");
		}
		initSampling(sampling);
		dao.insert(sampling);
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.ADD, null);
	}

	/**
	 * 初始化参数
	 *
	 * @author yuanshuai
	 * @date 2023/5/22 17:48
	 */
	private void initSampling(Sampling sampling) {
		sampling.setBindType(0);
		sampling.setFlowState(0);
		sampling.preInsert();
	}

	/**
	 * 修改采样包 仅能修改备注
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:27
	 */
	@Transactional(readOnly = false)
	public void update(Sampling sampling) {
		sampling.preUpdate();
		dao.updateRemarks(sampling);
	}

	/**
	 * 删除采样包
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 14:28
	 */
	@Transactional(readOnly = false)
	public void delete(Sampling sampling) {
		if (StringUtils.isNotBlank(sampling.getMemberCode())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "已有归属人采样包不可删除");
		}
		if (1 == sampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "已绑定采样包不可删除");
		}
		super.delete(sampling);
	}

	/**
	 * 导入采样包
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 10:31
	 */
	@Transactional(readOnly = false)
	public void importSampling(MultipartFile file) throws InvalidFormatException, IOException, InstantiationException,
			IllegalAccessException, InvocationTargetException {
		ImportExcel ei = new ImportExcel(file, 1, 0);
		List<SamplingImportVo> list = ei.getDataList(SamplingImportVo.class);
		List<Sampling> insertList = Lists.newArrayList();
		List<SamplingFlowLog> logList = Lists.newArrayList();
		boolean error = false;
		StrBuilder strBuilder = new StrBuilder();
		int i = 3;
		// 校验采样包编号文档内重复
		List<String> docDuplicateList = list.stream().map(SamplingImportVo::getSamplingCode)
				.filter(StringUtils::isNotBlank).collect(Collectors
						.collectingAndThen(Collectors.groupingBy(Function.identity(), Collectors.counting()), map -> {
							map.values().removeIf(size -> size == 1);
							return new ArrayList<>(map.keySet());
						}));
		// 校验采样包编号数据库内重复
		List<Sampling> samplingList = findListBySamplingCodeList(list.stream().map(SamplingImportVo::getSamplingCode)
				.filter(StringUtils::isNotBlank).collect(Collectors.toList()));
		List<String> dbDuplicateList = null;
		if (!CollectionUtils.isEmpty(samplingList)) {
			dbDuplicateList = samplingList.stream().map(Sampling::getSamplingCode).filter(StringUtils::isNotBlank)
					.collect(Collectors.toList());
		}

		for (int j = 0; j < list.size(); j++) {
			SamplingImportVo vo = list.get(j);
			if (StringUtils.isBlank(vo.getSamplingCode()) && j == list.size() - 1) {
				break;
			}
			if (StringUtils.isBlank(vo.getSamplingCode())) {
				error = recordError(strBuilder, "第" + i + "行，采样包编号不能为空");
			}
			if (!CollectionUtils.isEmpty(dbDuplicateList) && dbDuplicateList.contains(vo.getSamplingCode())) {
				error = recordError(strBuilder, "第" + i + "行，采样包编号已存在");
			}
			if (!CollectionUtils.isEmpty(docDuplicateList) && docDuplicateList.contains(vo.getSamplingCode())) {
				error = recordError(strBuilder, "第" + i + "行，采样包编号文档内重复");
			}

			if (!error) {
				Sampling sampling = new Sampling();
				BeanUtil.copyProperties(sampling, vo, "yyyy-MM-dd hh:mm:ss");
				initSampling(sampling);
				insertList.add(sampling);
				logList.add(samplingFlowLogService.initAddLog(sampling));
			}
			i++;
		}
		if (error) {
			throw new ZAException(ZAErrorCode.ZA_ERROR, strBuilder.toString());
		} else {
			batchInsert(insertList);
			samplingFlowLogService.batchInsert(logList);
		}
	}

	private boolean recordError(StrBuilder strBuilder, String msg) {
		strBuilder.append(msg).append("##");
		return true;
	}

	/**
	 * 导出
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 11:30
	 */
	public void export(Sampling sampling, HttpServletResponse response) throws IOException {
		//更换状态入参
		if (Objects.nonNull(sampling.getFlowState())
				&& (0 == sampling.getFlowState() || 1 == sampling.getFlowState())) {
			sampling.setBindType(sampling.getFlowState());
			sampling.setFlowState(null);
		}
		List<Sampling> samplingList = findList(sampling);
		List<SamplingExportVo> respList = Lists.newArrayList();
		samplingList.forEach(s -> {
			SamplingExportVo vo = SamplingExportVo.builder().build();
			BeanUtil.copyProperties(vo, s, "yyyy-MM-dd hh:mm:ss");
			Integer state = s.getFlowState();
			if (SamplingFlowStateEnum.SEND.code() >= s.getFlowState()) {
				state = s.getBindType();
			}
			vo.setState(DictUtils.getDictLabel(state.toString(), "sampling_flow_state_front", null));
			respList.add(vo);
		});
		ExportExcel exportExcel = new ExportExcel("采样包", SamplingExportVo.class, 1).setDataList(respList)
				.write(response, "采样包信息.xlsx").dispose();
	}

	/**
	 * 导出犬只信息
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 11:30
	 */
	public void exportDogInfo(Sampling sampling, HttpServletResponse response) throws IOException {
		//更换状态入参
		if (Objects.nonNull(sampling.getFlowState())
				&& (0 == sampling.getFlowState() || 1 == sampling.getFlowState())) {
			sampling.setBindType(sampling.getFlowState());
			sampling.setFlowState(null);
		}
		List<Sampling> samplingList = findList(sampling);
		List<SamplingDogExportVo> respList = Lists.newArrayList();
		samplingList.forEach(s -> {
			SamplingDogExportVo vo = SamplingDogExportVo.builder()
					.samplingCode(s.getSamplingCode())
					.petType("犬")
					.build();
			if (StringUtils.isNotBlank(s.getDogId())) {
				Dog dog = dogService.get(s.getDogId());
				if (Objects.nonNull(dog)) {
					vo.setChipNo(dog.getIdentificationFlag());
					vo.setBreedCode(dog.getDogBreed());
					vo.setGender(DictUtils.getDictLabel(dog.getGender(), "dog_gender", null));
					vo.setBirthdate(dog.getBirthdate());
					vo.setNickname(StringUtils.isBlank(dog.getCallName()) ? dog.getNameEn() : dog.getCallName());
				}
			} else {
				if (SamplingDogSourceTypeEnum.BIRTH_CODE.code().equals(s.getDogSourceType())) {
					// 出生纸
					DogBirthCertificate birthCertificate = dogBirthCertificateDao.getByBirthCerRegCode(s.getDogCode());
					if (Objects.nonNull(birthCertificate)) {
						vo.setChipNo(birthCertificate.getIdentificationFlag());
						vo.setBreedCode(birthCertificate.getDogBreed());
						vo.setGender(DictUtils.getDictLabel(birthCertificate.getDogGender(), "dog_gender", null));
						vo.setBirthdate(birthCertificate.getDogBirthday());
						DogChip dogChip = dogChipService.getByBirthCode(birthCertificate.getBirthCerRegCode());
						if (Objects.nonNull(dogChip) && StringUtils.isNotBlank(dogChip.getCallName())) {
							vo.setNickname(dogChip.getCallName());
						} else {
							vo.setNickname(birthCertificate.getDogEnName());
						}
					}
				} else if (SamplingDogSourceTypeEnum.OVERSEAS_PEDIGREE_CERTIFIED.code().equals(s.getDogSourceType())) {
					// 国外证书换发
					DogPedigreeCertifiedChange overseas = dogPedigreeCertifiedChangeDao.getByOverseasPedigreeCertified(s.getDogCode());
					if (Objects.nonNull(overseas)) {
						vo.setChipNo(overseas.getDogChip());
						vo.setBreedCode(overseas.getDogBreed());
						vo.setGender(DictUtils.getDictLabel(overseas.getDogGender(), "dog_gender", null));
						vo.setBirthdate(overseas.getDogBirthday());
						vo.setNickname(StringUtils.isBlank(overseas.getCallName()) ? overseas.getDogName() : overseas.getCallName());
					}
				}
			}
			respList.add(vo);
		});
		ExportExcel exportExcel = new ExportExcel("采样包绑定信息", SamplingDogExportVo.class, 1).setDataList(respList)
				.write(response, "采样包犬只信息.xlsx").dispose();
	}

	/**
	 * 邮寄
	 *
	 * @param memberCode          会员号(2268)或俱乐部会员号（HZ000400）
	 * @param distributionChannel 请使用SamplingDistributionChannelEnum标明会员或俱乐部
	 * @author yuanshuai
	 * @date 2023/5/23 16:23
	 */
	@Transactional(readOnly = false)
	public void post(String samplingCode, String memberCode, SamplingDistributionChannelEnum distributionChannel, Boolean checkFlag) {
		Sampling sampling = findBySamplingCode(samplingCode);
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id有误");
		}
		if (checkFlag && Objects.nonNull(sampling.getBindType()) && 1 == sampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已绑定无法邮寄");
		}
		if (checkFlag && Objects.nonNull(sampling.getFlowState())
				&& !SamplingFlowStateEnum.NO_USE.code().equals(sampling.getFlowState())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包状态有误无法邮寄");
		}
		// 更新邮寄信息
		sampling.setDistributionChannel(distributionChannel.code());
		sampling.setMemberCode(memberCode);
		String memberName = null;
		if (SamplingDistributionChannelEnum.MEMBER.code().equals(distributionChannel.code())) {
			Member member = memberService.getByMemberCode(memberCode);
			if (Objects.isNull(member) || StringUtils.isBlank(member.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "邮寄会员号信息有误");
			}
			memberName = member.getName();
		} else if (SamplingDistributionChannelEnum.ORG.code().equals(distributionChannel.code())) {
			Org org = orgService.getByMemberCode(memberCode);
			if (Objects.isNull(org) || StringUtils.isBlank(org.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "邮寄会员号信息有误");
			}
			memberName = org.getName();
		}
		sampling.setMemberName(memberName);
		sampling.preUpdate();
		dao.updatePostInfo(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.POST, memberCode + memberName);
	}

	/**
	 * 解绑会员信息
	 *
	 * @author yuanshuai
	 * @date 2023/5/29 11:02
	 */
	@Transactional(readOnly = false)
	public void unbindMemberInfo(Sampling sampling) {
		if (Objects.equals(SamplingFlowStateEnum.NO_USE.code(), sampling.getFlowState())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包没有关联会员信息，无法解除");
		}
		if (SamplingFlowStateEnum.POST.code() < sampling.getFlowState()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已使用，无法解除关联会员关系");
		}
		dao.updateUnbindMemberInfo(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.UNBIND_MEMBER,
				sampling.toString());
	}

	/**
	 * 批量邮寄
	 *
	 * @author yuanshuai
	 * @date 2023/5/28 16:46
	 */
	@Transactional(readOnly = false)
	public void batchPost(List<Sampling> samplingList, SamplingDistributionChannelEnum distributionChannel,
						  String memberCode, String memberName, String remarks) {
		// 获取操作人
		User user = UserUtils.getLoginUser();
		// 更新邮寄信息
		dao.batchUpdatePostInfo(samplingList.stream().map(BaseEntity::getId).collect(Collectors.toList()),
				distributionChannel.code(), memberCode, memberName, user.getId(), DateUtils.getNow(), remarks);
		// 记录日志
		Date operTime = DateUtils.getNow();
		String operBy = UserUtils.getLoginUser().getId();
		samplingFlowLogService.batchAdd(samplingList, SamplingLogFlowTypeEnum.POST, operTime, operBy);
	}

	/**
	 * 批量解绑会员信息
	 *
	 * @author yuanshuai
	 * @date 2023/5/29 11:30
	 */
	@Transactional(readOnly = false)
	public void batchUnbindMemberInfo(List<Sampling> samplingList) {
		if (samplingList.stream()
				.anyMatch(s -> Objects.equals(SamplingFlowStateEnum.NO_USE.code(), s.getFlowState()))) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包没有关联会员信息，无法解除");
		}
		if (samplingList.stream().anyMatch(s -> SamplingFlowStateEnum.POST.code() < s.getFlowState())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已使用，无法解除关联会员关系");
		}
		Date operTime = DateUtils.getNow();
		String operBy = UserUtils.getLoginUser().getId();
		dao.batchUpdateUnbindMemberInfo(samplingList.stream().map(BaseEntity::getId).collect(Collectors.toList()),
				operBy, operTime, null);
		// 记录日志
		samplingFlowLogService.batchAdd(samplingList, SamplingLogFlowTypeEnum.UNBIND_MEMBER, operTime, operBy);
	}

	/**
	 * 绑定采样包
	 *
	 * @param dogCode       犬只编号：血统证书、出生纸或国外证书号
	 * @param dogSourceType 请使用SamplingDogSourceTypeEnum标明犬只编号是哪个
	 * @author yuanshuai
	 * @date 2023/5/24 16:41
	 */
	@Transactional(readOnly = false)
	public void bind(String samplingCode, String dogCode, SamplingDogSourceTypeEnum dogSourceType, Boolean checkFlag) {
		Sampling sampling = findBySamplingCode(samplingCode);
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号有误");
		}
		if (checkFlag && Objects.nonNull(sampling.getBindType()) && 1 == sampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已绑定无法再次绑定");
		}
		if (Objects.nonNull(sampling.getFlowState())
				&& Objects.equals(sampling.getFlowState(), SamplingFlowStateEnum.LOGOUT.code())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已注销无法绑定");
		}
		// 更新绑定信息
		sampling.setDogSourceType(dogSourceType.code());
		sampling.setDogCode(dogCode);
		// 校验犬只信息
		if (SamplingDogSourceTypeEnum.PEDIGREE_CERTIFIED.code().equals(dogSourceType.code())) {
			// 如果是血统证书，更新犬只ID
			Dog dog = dogService.getByPedigreeCertifiedCode(dogCode);
			if (Objects.isNull(dog) || StringUtils.isBlank(dog.getId())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "绑定犬只信息有误，没有查到该证书号对应犬只");
			} else {
				sampling.setDogId(dog.getId());
			}
		} else if (SamplingDogSourceTypeEnum.BIRTH_CODE.code().equals(dogSourceType.code())) {
			// 出生纸
			DogBirthCertificate birthCertificate = dogBirthCertificateDao.getByBirthCerRegCode(dogCode);
			if (Objects.isNull(birthCertificate) || StringUtils.isBlank(birthCertificate.getId())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "绑定犬只信息有误，没有查到该证书号对应犬只");
			} else if (!StringUtils.isBlank(birthCertificate.getPedigreeCertified())) {
				Dog dog = dogService.getByPedigreeCertifiedCode(birthCertificate.getPedigreeCertified());
				if (!StringUtils.isBlank(dog.getId())) {
					sampling.setDogId(dog.getId());
				}
			}
		} else if (SamplingDogSourceTypeEnum.OVERSEAS_PEDIGREE_CERTIFIED.code().equals(dogSourceType.code())) {
			// 国外证书换发
			DogPedigreeCertifiedChange overseas = dogPedigreeCertifiedChangeDao.getByOverseasPedigreeCertified(dogCode);
			if (Objects.isNull(overseas) || StringUtils.isBlank(overseas.getId())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "绑定犬只信息有误，没有查到该证书号对应犬只");
			}
			if (!StringUtils.isBlank(overseas.getDogId())) {
				sampling.setDogId(overseas.getDogId());
			}
		}
		// 操作人信息
		User user = UserUtils.getLoginUser();
		sampling.setBindType(1);
		sampling.setBindBy(user.getId());
		if ("1".equals(user.getUserType())) {
			// 后台
			sampling.setBindUserName(user.getName());
		} else if ("3".equals(user.getUserType())) {
			// 俱乐部
			Org org = (Org) UserUtils.getSession().getAttribute("org");
			if (Objects.isNull(org) || StringUtils.isBlank(org.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "绑定的会员号信息有误");
			}
			sampling.setBindMemberCode(org.getMemberCode());
			sampling.setBindUserName(org.getName());
		} else if ("2".equals(user.getUserType()) || "4".equals(user.getUserType()) || "6".equals(user.getUserType())) {
			Member member = memberService.getByUserId(user.getId());
			if (Objects.isNull(member) || StringUtils.isBlank(member.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "绑定的会员号信息有误");
			}
			sampling.setBindMemberCode(member.getMemberCode());
			sampling.setBindUserName(member.getName());
		}
		sampling.setBindTime(DateUtils.getNow());
		sampling.preUpdate();
		dao.updateBindInfo(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.BIND, dogCode);
	}

	@Transactional(readOnly = false)
	public Sampling reissueBind(String newSamplingCode, String oldSamplingCode, String memberCode, String memberName,
								String reissueRemarks) {
		Sampling sampling = findBySamplingCode(newSamplingCode);
		Sampling oldSampling = findBySamplingCode(oldSamplingCode);
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号有误");
		}
		if (Objects.nonNull(sampling.getBindType()) && 1 == sampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已绑定无法再次绑定");
		}
		if (Objects.nonNull(sampling.getFlowState())
				&& Objects.equals(sampling.getFlowState(), SamplingFlowStateEnum.LOGOUT.code())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已注销无法绑定");
		}
		if (Objects.isNull(oldSampling) || StringUtils.isBlank(oldSampling.getId()) || 1 != oldSampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "原采样包编号有误，或处于未绑定状态，无法解绑");
		}
		// 绑定新采样包，不改变原采样包归属人，以便删除订单时的恢复操作
		sampling.setDogId(oldSampling.getDogId());
		sampling.setDogSourceType(oldSampling.getDogSourceType());
		sampling.setDogCode(oldSampling.getDogCode());
		sampling.setMemberCode(memberCode);
		sampling.setMemberName(memberName);
		// 操作人信息
		User user = UserUtils.getLoginUser();
		sampling.setBindType(1);
		sampling.setBindBy(user.getId());
		// 后台
		sampling.setBindUserName(user.getName());
		sampling.setBindTime(DateUtils.getNow());
		sampling.preUpdate();
		dao.updateBindInfoMore(sampling);
		// 修改原采样包状态为失败
		this.updateFlowState(oldSampling, SamplingFlowStateEnum.FAILURE, reissueRemarks, "DNA存档采样包补寄解绑");
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.BIND, oldSampling.getDogCode());
		return sampling;
	}

	@Transactional(readOnly = false)
	public Sampling reissueUnBind(String newSamplingCode, String oldSamplingCode) {
		Sampling oldSampling = findBySamplingCode(oldSamplingCode);
		Sampling newSampling = findBySamplingCode(newSamplingCode);
		if (Objects.isNull(newSampling) || StringUtils.isBlank(newSampling.getId()) || Objects.isNull(oldSampling)
				|| StringUtils.isBlank(oldSampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号有误");
		}
		if (Objects.nonNull(newSampling.getBindType()) && 1 == newSampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包未绑定无法解绑");
		}
		if (Objects.nonNull(newSampling.getFlowState()) && 1 == newSampling.getFlowState()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已邮寄无法解绑");
		}
		newSampling.setDogId(null);
		newSampling.setDogSourceType(null);
		newSampling.setDogCode(null);
		newSampling.setBindMemberCode(null);
		newSampling.setBindType(0);
		newSampling.setBindBy(null);
		newSampling.setBindUserName(null);
		newSampling.setBindTime(null);
		newSampling.preUpdate();
		newSampling.preUpdate();
		dao.updateBindInfo(newSampling);
		// 恢复原采样包绑定状态
		this.updateFlowState(oldSampling, SamplingFlowStateEnum.NO_USE, null, "DNA存档采样包补寄删除恢复");
		// 记录日志
		samplingFlowLogService.add(newSampling.getSamplingCode(), SamplingLogFlowTypeEnum.UNBIND_DOG,
				oldSampling.getDogCode());
		return newSampling;
	}

	/**
	 * 解除绑定信息
	 *
	 * @author yuanshuai
	 * @date 2023/5/29 10:23
	 */
	@Transactional(readOnly = false)
	public void unbindDogInfoBySamplingCode(String samplingCode) {
		Sampling sampling = findBySamplingCode(samplingCode);
		unbindDogInfo(sampling);
	}

	/**
	 * 解除绑定信息
	 *
	 * @param sampling 请先查询数据库中采样包数据
	 * @author yuanshuai
	 * @date 2023/5/29 10:23
	 */
	@Transactional(readOnly = false)
	public void unbindDogInfo(Sampling sampling) {
		if (0 == sampling.getBindType()) {
			return;
		}
		sampling.preUpdate();
		dao.updateUnbindDogInfo(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.UNBIND_DOG, sampling.toString());
	}

	/**
	 * 送检
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 16:23
	 */
	@Transactional(readOnly = false)
	public void send(String id) {
		Sampling sampling = get(id);
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id有误");
		}
		if (Objects.nonNull(sampling.getBindType()) && 0 == sampling.getBindType()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包未绑定无法进行送检");
		}
		if (Objects.nonNull(sampling.getFlowState()) && sampling.getFlowState() >= SamplingFlowStateEnum.SEND.code()) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包状态有误无法送检");
		}
		sampling.setFlowState(SamplingFlowStateEnum.SEND.code());
		sampling.setSendTime(DateUtils.getNow());
		sampling.preUpdate();
		dao.updateSend(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), SamplingLogFlowTypeEnum.SEND, null);
	}

	/**
	 * 注销采样包
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 16:05
	 */
	@Transactional(readOnly = false)
	public void logout(String id, String remarks) {
		Sampling sampling = get(id);
		logout(sampling, remarks, null);
	}

	/**
	 * 注销采样包
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 16:05
	 */
	@Transactional(readOnly = false)
	public void logout(Sampling sampling, String remarks, String logData) {
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id有误");
		}
		if (Objects.nonNull(sampling.getFlowState())
				&& Objects.equals(sampling.getFlowState(), SamplingFlowStateEnum.LOGOUT.code())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已注销无法再次注销");
		}
		updateFlowState(sampling, SamplingFlowStateEnum.LOGOUT, remarks, logData);
	}

	/**
	 * 根据采样包编号上传结果
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 10:25
	 */
	@Transactional(readOnly = false)
	public void resultBySamplingCode(String samplingCode, SamplingFlowStateEnum flowState, String remark,
									 String logData, Boolean isOa) {
		Sampling sampling = findBySamplingCode(samplingCode);
		result(sampling, flowState, remark, logData, isOa);
	}

	/**
	 * 根据采样包ID上传结果
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 10:25
	 */
	@Transactional(readOnly = false)
	public void resultById(String id, Integer flowState, String remarks, String logData, Boolean isOa) {
		Sampling sampling = get(id);
		result(sampling, IEnum.codeOf(SamplingFlowStateEnum.class, flowState).orElse(null), remarks, logData, isOa);
	}

	/**
	 * 采样包上传结果
	 *
	 * @author yuanshuai
	 * @date 2023/5/25 10:25
	 */
	@Transactional(readOnly = false)
	public void result(Sampling sampling, SamplingFlowStateEnum flowState, String remarks, String logData,
					   Boolean isOa) {
		if (Objects.isNull(sampling) || StringUtils.isBlank(sampling.getId())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id有误");
		}
		if (Objects.isNull(sampling.getFlowState())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "检测结果为空");
		}
		if (!Objects.equals(SamplingFlowStateEnum.SUCCESS.code(), flowState.code())
				&& !Objects.equals(SamplingFlowStateEnum.FAILURE.code(), flowState.code())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包检测结果只能为成功或者失败");
		}
//		if (isOa && Objects.nonNull(sampling.getFlowState())
//				&& !Objects.equals(sampling.getFlowState(), SamplingFlowStateEnum.SEND.code())) {
//			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "只有已送检采样包可以上传结果");
//		}
		updateFlowState(sampling, flowState, remarks, logData);
	}

	/**
	 * 更改流程状态并记录日志
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 16:38
	 */
	@Transactional(readOnly = false)
	public void updateFlowState(Sampling sampling, SamplingFlowStateEnum state, String remarks, String logData) {
		sampling.setFlowState(state.code());
		sampling.setRemarks(remarks);
		sampling.preUpdate();
		dao.updateFlowState(sampling);
		// 记录日志
		samplingFlowLogService.add(sampling.getSamplingCode(), samplingFlowLogService.flowState2LogFlowType(state),
				logData);
	}

	/**
	 * 更改流程状态并记录日志
	 *
	 * @author yuanshuai
	 * @date 2023/5/23 16:38
	 */
	@Transactional(readOnly = false)
	public void updateFlowState(String samplingCode, SamplingFlowStateEnum state, String remarks, String logData) {
		Sampling sampling = this.findBySamplingCode(samplingCode);
		if (Objects.isNull(sampling)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包数据有误");
		}
		updateFlowState(sampling, state, remarks, logData);
	}

	/**
	 * 批量送检
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 10:58
	 */
	@Transactional(readOnly = false)
	public void batchSend(List<Sampling> requestList) {
		if (CollectionUtils.isEmpty(requestList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id列表为空");
		}
		List<Sampling> samplingList = findListByIdList(requestList.stream().map(Sampling::getId)
				.filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList()));
		if (CollectionUtils.isEmpty(samplingList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id列表有误");
		}
		if (samplingList.stream().anyMatch(s -> Objects.nonNull(s.getBindType()) && 0 == s.getBindType())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包未绑定无法进行送检");
		}
		if (samplingList.stream().anyMatch(
				s -> Objects.nonNull(s.getFlowState()) && s.getFlowState() >= SamplingFlowStateEnum.SEND.code())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包状态有误无法送检");
		}
		// 更新送检
		Date operTime = DateUtils.getNow();
		String operBy = UserUtils.getLoginUser().getId();
		dao.batchUpdateSend(samplingList.stream().map(Sampling::getId).filter(StringUtils::isNotBlank).distinct()
				.collect(Collectors.toList()), SamplingFlowStateEnum.SEND.code(), operBy, operTime);
		// 记录日志
		samplingFlowLogService.batchAdd(samplingList, SamplingLogFlowTypeEnum.SEND, operTime, operBy);
	}

	/**
	 * 批量更改流程状态并记录日志
	 *
	 * @author yuanshuai
	 * @date 2023/5/24 11:28
	 */
	@Transactional(readOnly = false)
	public void batchUpdateFlowState(List<Sampling> samplingList, SamplingFlowStateEnum state, String remark) {
		Date operTime = DateUtils.getNow();
		String operBy = UserUtils.getLoginUser().getId();
		dao.batchUpdateFlowState(samplingList.stream().map(Sampling::getId).filter(StringUtils::isNotBlank).distinct()
				.collect(Collectors.toList()), state.code(), operBy, operTime, remark);
		// 记录日志
		samplingFlowLogService.batchAdd(samplingList, samplingFlowLogService.flowState2LogFlowType(state), operTime,
				operBy);
	}

	/**
	 * 采样包是否可用
	 *
	 * @param samplingCode
	 * @param memberCode
	 */
	public void checkSamplingCode(String samplingCode, String memberCode) {
		Sampling sampling = findBySamplingCode(samplingCode);
		if (sampling == null) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号错误");
		}
		if (!Objects.equals(sampling.getMemberCode(), memberCode)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包编号错误");
		}
		if (sampling.getBindType() == 1) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已绑定");
		}
		if (sampling.getFlowState() != 1) {
			// 流程状态（0待邮寄，1已邮寄，2已送检，3检测成功，4检测失败，5已注销）不能为空
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包状态异常");
		}
	}

	public Sampling getByDogCode(String dogCode, SamplingDogSourceTypeEnum dogSourceType) {
		return dao.getByDogCode(dogCode, dogSourceType.code());
	}

	/**
	 * 邮寄
	 *
	 * @param memberCode          会员号(2268)或俱乐部会员号（HZ000400）
	 * @param distributionChannel 请使用SamplingDistributionChannelEnum标明会员或俱乐部
	 * @author yuanshuai
	 * @date 2023/5/23 16:23
	 */
	@Transactional(readOnly = false)
	public void batchExpress(List<String> samplingCodeList, String memberCode,
							 SamplingDistributionChannelEnum distributionChannel) {
		List<Sampling> samplingList = findListBySamplingCodeList(samplingCodeList);
		if (CollectionUtils.isEmpty(samplingList)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包id有误");
		}
		if (samplingList.stream()
				.anyMatch(sampling -> Objects.nonNull(sampling.getBindType()) && 1 == sampling.getBindType())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包已绑定无法邮寄");
		}
		if (samplingList.stream().anyMatch(sampling -> Objects.nonNull(sampling.getFlowState())
				&& !SamplingFlowStateEnum.NO_USE.code().equals(sampling.getFlowState()))) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包状态有误无法邮寄");
		}

		String memberName = null;
		if (SamplingDistributionChannelEnum.MEMBER.code().equals(distributionChannel.code())) {
			Member member = memberService.getByMemberCode(memberCode);
			if (Objects.isNull(member) || StringUtils.isBlank(member.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "邮寄会员号信息有误");
			}
			memberName = member.getName();
		} else if (SamplingDistributionChannelEnum.ORG.code().equals(distributionChannel.code())) {
			Org org = orgService.getByMemberCode(memberCode);
			if (Objects.isNull(org) || StringUtils.isBlank(org.getName())) {
				throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "邮寄会员号信息有误");
			}
			memberName = org.getName();
		}

		// 获取操作人
		User user = UserUtils.getLoginUser();
		// 更新邮寄信息
		dao.batchUpdatePostInfo(samplingList.stream().map(BaseEntity::getId).collect(Collectors.toList()),
				distributionChannel.code(), memberCode, memberName, user.getId(), DateUtils.getNow(), null);
		Date operTime = DateUtils.getNow();
		String operBy = UserUtils.getLoginUser().getId() + "(" + memberCode + memberName + ")";
		// 记录日志
		samplingFlowLogService.batchAdd(samplingList, SamplingLogFlowTypeEnum.POST, operTime, operBy);
	}

	/**
	 * 更新犬只ID
	 *
	 * @author yuanshuai
	 * @date 2023/7/27 10:08
	 */
	public void updateDogId(String id, String dogId) {
		if (StringUtils.isBlank(id) || StringUtils.isBlank(dogId)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包ID或犬只ID为空");
		}
		dao.updateDogId(id, dogId);
	}

	/**
	 * 更新犬只信息
	 *
	 * @author yuanshuai
	 * @date 2024年3月29日10:38:23
	 */
	public void updateDogInfo(Sampling sampling) {
		if (Objects.isNull(sampling)) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "采样包信息为空");
		}
		sampling.preUpdate();
		dao.updateDogInfo(sampling);
	}

}
