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

import com.prolog.cs.biz.inbound.constant.VaildateConstant;
import com.prolog.cs.biz.inbound.constant.ValidatorGroup.validAdd;
import com.prolog.cs.biz.inbound.constant.ValidatorGroup.validEdit;
import com.prolog.cs.biz.inbound.dao.rqc.RqcRechekLinesMapper;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.rqc.RqcRechekLinesDTO;
import com.prolog.cs.biz.inbound.model.rqc.RqcRechekLines;
import com.prolog.cs.biz.inbound.service.rqc.RqcRechekLinesService;
import com.prolog.cs.biz.inbound.service.task.TaskInstockDetailService;
import com.prolog.cs.biz.inbound.service.task.TaskQcDetailService;
import com.prolog.cs.biz.inbound.service.task.TaskQcRecheckDetailService;
import com.prolog.cs.biz.inbound.service.task.TaskRejectedDetailService;
import com.prolog.cs.biz.inbound.utils.ObjectUtils;
import com.prolog.cs.biz.inbound.utils.UserUtils;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
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.dao.util.PageUtils;
import com.prolog.framework.utils.AssertUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class RqcRechekLinesServiceImpl implements RqcRechekLinesService {

	@Resource
	private RqcRechekLinesMapper mapper;

	@Resource
	private UserUtils userUtils;
	
	@Resource
	private TaskInstockDetailService taskInstockDetailService;
	
	@Resource
	private TaskQcDetailService taskQcDetailService;
	
	@Resource
	private TaskQcRecheckDetailService taskQcRecheckDetailService;
	
	@Resource
	private TaskRejectedDetailService taskRejectedDetailService;


	@Override
	public Object add(RqcRechekLinesDTO rqcRechekLinesDTO) {
		// TODO vaildate
		UserDTO userDTO = userUtils.getUserDTO();
		RqcRechekLines rqcRechekLines = new RqcRechekLines();
		BeanUtils.copyProperties(rqcRechekLinesDTO, rqcRechekLines);
		this.vaildateModel(rqcRechekLines, false, userDTO);
		this.buildField(rqcRechekLines, false, userDTO);
		this.mapper.save(rqcRechekLines);
		return "";
	}

	@Override
	public Object edit(String pkId, RqcRechekLinesDTO rqcRechekLinesDTO) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		RqcRechekLines rqcRechekLines = new RqcRechekLines();
		BeanUtils.copyProperties(rqcRechekLinesDTO, rqcRechekLines);
		this.vaildateModel(rqcRechekLines, true, userDTO);
		this.buildField(rqcRechekLines, true, userDTO);
		this.mapper.updateWithValidate(rqcRechekLines,
				p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
		return "";
	}

	@Override
	@Transactional
	public Object delIds(List<String> pkIdList) {
		// TODO
		pkIdList.stream().filter(p -> canEdit(p)).forEach(p -> this.mapper.deleteById(p, RqcRechekLines.class));
		return "";
	}

	@Override
	public Object deletePkId(String pkId) {
		// TODO
		if (canEdit(pkId))
			throw new BizException("can not del");
		this.mapper.deleteById(pkId, RqcRechekLines.class);
		return "";
	}

	@Override
	public Page<RqcRechekLinesDTO> findList(RqcRechekLinesDTO rqcRechekLinesDTO, PageParam pageParam) {
		Criteria criteria = Criteria.forClass(RqcRechekLines.class);
		Integer pageNum = null;
		Integer pageSize = null;
		Restriction r = null;
		if (pageParam == null) {
			pageNum = PageParam.DEFAULT_PAGE_NUM;
			pageSize = PageParam.DEFAULT_PAGE_SIZE;
		} else {
			pageNum = pageParam.getPageNum();
			pageSize = pageParam.getPageSize();
			RqcRechekLinesDTO condition = rqcRechekLinesDTO;
			r = buildCondition(condition);
		}
		if (pageNum == null || pageNum == 0) {
			pageNum = PageParam.DEFAULT_PAGE_NUM;
		}
		if (pageSize == null || pageSize == 0) {
			pageSize = PageParam.DEFAULT_PAGE_SIZE;
		}
		criteria.setRestriction(r);
		Order order = Order.newInstance().desc("gmtModified");
		criteria.setOrder(order);
		PageUtils.startPage(pageNum, pageSize);
		List<RqcRechekLines> list = this.mapper.findByCriteria(criteria);
		List<RqcRechekLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
			RqcRechekLinesDTO target = new RqcRechekLinesDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		}).collect(Collectors.toList());
		Page<RqcRechekLines> page = PageUtils.getPage(list);
		Page<RqcRechekLinesDTO> page2 = new Page<>();
		page2.setStartRow(page.getStartRow());
		page2.setEndRow(page.getEndRow());
		page2.setPageCount(page.getPageCount());
		page2.setPageNum(page.getPageNum());
		page2.setPageSize(page.getPageSize());
		page2.setTotalCount(page.getTotalCount());
		page2.setList(collect);
		return page2;
	}

	@Override
	@Transactional
	public Object batchAdd(List<RqcRechekLinesDTO> rqcRechekLinesDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		for (RqcRechekLinesDTO rqcRechekLinesDTO : rqcRechekLinesDTOList) {
			RqcRechekLines rqcRechekLines = new RqcRechekLines();
			BeanUtils.copyProperties(rqcRechekLinesDTO, rqcRechekLines);
			this.vaildateModel(rqcRechekLines, false, userDTO);
			this.buildField(rqcRechekLines, false, userDTO);
			this.mapper.save(rqcRechekLines);
		}
		return "";
	}

	@Override
	@Transactional
	public Object batchEdit(List<RqcRechekLinesDTO> rqcRechekLinesDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		for (RqcRechekLinesDTO rqcRechekLinesDTO : rqcRechekLinesDTOList) {
			RqcRechekLines rqcRechekLines = new RqcRechekLines();
			BeanUtils.copyProperties(rqcRechekLinesDTO, rqcRechekLines);
			this.vaildateModel(rqcRechekLines, true, userDTO);
			this.buildField(rqcRechekLines, true, userDTO);
			this.mapper.updateWithValidate(rqcRechekLines,
					p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
		}
		return "";
	}

	@Override
	public List<RqcRechekLinesDTO> findAll(RqcRechekLinesDTO rqcRechekLinesDTO) {
		// TODO
		Criteria criteria = Criteria.forClass(RqcRechekLines.class);
		RqcRechekLinesDTO condition = rqcRechekLinesDTO;
		Restriction r = buildCondition(condition);
		criteria.setRestriction(r);
		Order order = Order.newInstance().desc("gmtModified");
		criteria.setOrder(order);
		List<RqcRechekLines> list = this.mapper.findByCriteria(criteria);
		List<RqcRechekLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
			RqcRechekLinesDTO target = new RqcRechekLinesDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		}).collect(Collectors.toList());
		return collect;
	}

	@Override
	public RqcRechekLinesDTO findByPkId(String pkId) {
		// TODO
		RqcRechekLines rqcRechekLines = this.findById(pkId);
		AssertUtils.notNull(rqcRechekLines, "model empty!");
		RqcRechekLinesDTO rqcRechekLinesDTO = new RqcRechekLinesDTO();
		BeanUtils.copyProperties(rqcRechekLines, rqcRechekLinesDTO);
		return rqcRechekLinesDTO;
	}

	private RqcRechekLines findById(String id) {
		return this.mapper.findById(id, RqcRechekLines.class);
	}

	private void vaildateModel(RqcRechekLines rqcRechekLines, Boolean editFlag, UserDTO userDTO) {
		if (!editFlag) {
			// TODO add
		} else {
			// TODO
		}
	}

	private void buildField(RqcRechekLines rqcRechekLines, Boolean editFlag, UserDTO userDTO) {
		if (!editFlag) {
			// TODO add
		} else {
			// TODO edit
		}
		vaildateModelRepeated(rqcRechekLines, editFlag, userDTO);
	}

	private void vaildateModelRepeated(RqcRechekLines rqcRechekLines, Boolean editFlag, UserDTO userDTO) {
		if (!editFlag) {
			// TODO add
		} else {
			// TODO
		}
	}

	private boolean canEdit(String pkId) {
		boolean flag = true;
		RqcRechekLines rqcRechekLines = this.findById(pkId);
		AssertUtils.notNull(rqcRechekLines, "model empty!");
		// TODO
		if (true)
			flag = false;
		return flag;
	}

	private Restriction buildCondition(RqcRechekLinesDTO rqcRechekLinesDTO) {
		// TODO
		return null;
	}

	@Override
	public Object batchAdd(List<RqcRechekLinesDTO> rqcRechekLinesDTOList, String masterId, UserDTO userDTO, Date now) {
		// 批量添加
		// 批量添加
		if (ObjectUtils.isNull(userDTO))
			userDTO = userUtils.getUserDTO();
		if (ObjectUtils.isNull(now))
			now = new Date();
		int row = 0;
		boolean editFlag = Boolean.FALSE;
		for (RqcRechekLinesDTO rqcRechekLinesDTO : rqcRechekLinesDTOList) {
			row++;
			// 头表id
			String billno = rqcRechekLinesDTO.getBillno();
			if (ObjectUtils.isNull(billno))
				rqcRechekLinesDTO.setBillno(masterId);
			;

			this.buildDefaultField(rqcRechekLinesDTO, editFlag, userDTO);
			this.vaildateModel(rqcRechekLinesDTO, editFlag, userDTO, row);
			RqcRechekLines lines = new RqcRechekLines();
			BeanUtils.copyProperties(rqcRechekLinesDTO, lines);
			this.buildField(lines, editFlag, userDTO, now);
			// TODO 这里是否需要记录质检的次数及其操作信息
			this.mapper.save(lines);
		}
		// 根据质复检的结论分组到复检组,上架组 TODO
		 Map<String, List<RqcRechekLinesDTO>> collect = Optional.ofNullable(rqcRechekLinesDTOList).orElse(Collections.emptyList())
				.stream().distinct().collect(Collectors.groupingBy(RqcRechekLinesDTO :: getQcResult));
		 AssertUtils.notNull(collect, "复检行数据根据结论分组为空!");	
		 // 是否需要判断质检次数,复检次数
		 int times = 2; // 第二次入复检/质检
		 for (List<RqcRechekLinesDTO> rqcRechekLinesList : collect.values()) {
			 String conclusion = rqcRechekLinesList.get(0).getQcResult();
			 switch (conclusion) {
				case "0":
					// 完成 合格
					// 走质检任务池
					taskQcDetailService.excuteTask33(rqcRechekLinesList,conclusion,times);
					break;
				case "1":
					// 完成 不合格
					// 走质检任务池
					taskQcDetailService.excuteTask33(rqcRechekLinesList,conclusion,times);
					break;
				case "2":
					// 待处理
					// 走复检检任务池 是否需要根据次数选择池子的类型
					taskQcRecheckDetailService.excuteTask22(rqcRechekLinesList,times);
					break;
				case "3":
					// 拒收
					// 走拒收任务池
					taskRejectedDetailService.excuteTask33(rqcRechekLinesList);
					break;
				default:
					// 默认走质检任务池 合格
					taskQcDetailService.excuteTask33(rqcRechekLinesList,"0",times);
					break;
				}
		 }
		return true;
	}

	private void buildField(RqcRechekLines lines, boolean editFlag, UserDTO userDTO, Date now) {
		// 构建系统级字段

	}

	private void vaildateModel(RqcRechekLinesDTO rqcRechekLinesDTO, boolean editFlag, UserDTO userDTO, int row) {
		// 校验数据
		Set<ConstraintViolation<RqcRechekLinesDTO>> validate = null;
		if (!editFlag) {
			// 添加校验
			validate = validator.validate(rqcRechekLinesDTO, validAdd.class);
		} else {
			validate = validator.validate(rqcRechekLinesDTO, validEdit.class);
		}
		if (validate != null && !validate.isEmpty()) {
			StringBuilder sb = new StringBuilder();
			if (row > 0)
				sb.append(String.format(VaildateConstant.ERROR_ROW_FORMAT, row));
			validate.forEach((validation) -> {
				String errorMsg = validation.getMessage();
				String propertyName = validation.getPropertyPath().toString();
				sb.append(String.format(VaildateConstant.ERROR_FIELD_FORMAT, propertyName))
						.append(String.format(VaildateConstant.ERROR_MSG_FORMAT, errorMsg));
			});
			throw new ParameterException(sb.toString());
		}
	}

	private void buildDefaultField(RqcRechekLinesDTO rqcRechekLinesDTO, boolean editFlag, UserDTO userDTO) {
		// 构建默认字段

	}

	@Resource
	private Validator validator;
}
