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

import com.prolog.cs.biz.inbound.dao.rcv.RcvRejectLinesMapper;
import com.prolog.cs.biz.inbound.dao.task.TaskRejectedDetailMapper;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.rcv.RcvHDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvRejectLinesDTO;
import com.prolog.cs.biz.inbound.dto.task.TaskRejectedDetailDTO;
import com.prolog.cs.biz.inbound.model.rcv.RcvRejectLines;
import com.prolog.cs.biz.inbound.model.task.TaskRejectedDetail;
import com.prolog.cs.biz.inbound.service.impl.BaseServiceImpl;
import com.prolog.cs.biz.inbound.service.rcv.RcvRejectLinesService;
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.cs.biz.inbound.vo.RcvQueryVO;
import com.prolog.cs.biz.inbound.vo.TaskQcDQueryVO;
import com.prolog.cs.biz.inbound.vo.task.TaskQueryVO;
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.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.AssertUtils;
import com.prolog.framework.utils.MapUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class RcvRejectLinesServiceImpl extends BaseServiceImpl<RcvRejectLines> implements RcvRejectLinesService {

	@Resource
	private RcvRejectLinesMapper mapper;

	@Resource
	private UserUtils userUtils;

	@Resource
	private TaskRejectedDetailService taskRejectedDetailService;

	@Resource
	private TaskRejectedDetailMapper taskMapper;

	@Resource
	private Validator validator;

	@Override
	public Object add(RcvRejectLinesDTO rcvRejectLinesDTO) {
		// TODO vaildate
		UserDTO userDTO = userUtils.getUserDTO();
		RcvRejectLines rcvRejectLines = new RcvRejectLines();
		BeanUtils.copyProperties(rcvRejectLinesDTO, rcvRejectLines);
		this.vaildateModel(rcvRejectLines, false, userDTO);
		this.buildField(rcvRejectLines, false, userDTO, new Date());
		this.mapper.save(rcvRejectLines);
		return "";
	}

	@Override
	public Object edit(String pkId, RcvRejectLinesDTO rcvRejectLinesDTO) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		RcvRejectLines rcvRejectLines = new RcvRejectLines();
		BeanUtils.copyProperties(rcvRejectLinesDTO, rcvRejectLines);
		this.vaildateModel(rcvRejectLines, true, userDTO);
		this.buildField(rcvRejectLines, true, userDTO, new Date());
		this.mapper.updateWithValidate(rcvRejectLines,
				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, RcvRejectLines.class));
		return "";
	}

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

	@Override
	public Page<RcvRejectLinesDTO> findList(RcvRejectLinesDTO rcvRejectLinesDTO, PageParam pageParam) {
		Criteria criteria = Criteria.forClass(RcvRejectLines.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();
			RcvRejectLinesDTO condition = rcvRejectLinesDTO;
			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<RcvRejectLines> list = this.mapper.findByCriteria(criteria);
		List<RcvRejectLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
			RcvRejectLinesDTO target = new RcvRejectLinesDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		}).collect(Collectors.toList());
		Page<RcvRejectLines> page = PageUtils.getPage(list);
		Page<RcvRejectLinesDTO> 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<RcvRejectLinesDTO> rcvRejectLinesDTOList) {
		AssertUtils.isNotEmpty(rcvRejectLinesDTOList, "操作集合为空!");
		UserDTO userDTO = userUtils.getUserDTO();
		boolean editFlag = Boolean.FALSE;
		Date now = new Date();
		int row = 0;
		for (RcvRejectLinesDTO rcvRejectLinesDTO : rcvRejectLinesDTOList) {
			row++;
			// 数据准确性计算
			BigDecimal pieceQty = rcvRejectLinesDTO.getPieceQty();
			BigDecimal conversionRate = rcvRejectLinesDTO.getConversionRate();
			if (conversionRate == null) {
				conversionRate = BigDecimal.ONE;
				rcvRejectLinesDTO.setConversionRate(conversionRate);
			}
			if (pieceQty == null) {
				pieceQty = BigDecimal.ZERO;
				rcvRejectLinesDTO.setPieceQty(pieceQty);
			}
			excuteSave(row, rcvRejectLinesDTO, userDTO, now, editFlag);
		}
		// 此处需不需要判断上架收货完毕回传 待确认 TODO
		return true;
	}

	private void excuteSave(int row, RcvRejectLinesDTO rcvRejectLinesDTO, UserDTO userDTO, Date now, boolean editFlag) {
		String taskId = rcvRejectLinesDTO.getTaskId();
		// 并发校验
		// 加锁(数据库锁)
		boolean canCommit = canCommit(taskId, row);
		if (!canCommit)
			throw new BizException(String.format("第[%d行]保存拒收行失败!taskId为[%s]的拒收任务已处理中,请刷新重试!", row, taskId));

		this.vaildateModel(rcvRejectLinesDTO, editFlag, userDTO, row, validator, "批量新增拒收行操作");
		RcvRejectLines line = new RcvRejectLines();
		BeanUtils.copyProperties(rcvRejectLinesDTO, line);
		this.buildField(line, editFlag, userDTO, now);
		this.mapper.save(line);

	}

	private boolean canCommit(String taskId, int row) {
		// 数据库乐观锁
		TaskRejectedDetail task = this.taskMapper.findById(taskId, TaskRejectedDetail.class);
		AssertUtils.notNull(task, String.format("第[%d]行,拒收任务id:[%s]查询的任务为空!", row, taskId));
		String status = task.getStatus();
		if (!"1".equals(status))
			throw new BizException(String.format("第[%d]行,拒收任务id:[%s]查询的任务已经执行完毕,请刷新重试!", row, taskId));

		Criteria criteria = new Criteria(TaskRejectedDetail.class);
		Integer dataVersion = task.getDataVersion();

		criteria.setRestriction(Restrictions.and(Restrictions.eq("taskRejectedId", taskId),
				Restrictions.eq("dataVersion", dataVersion)));
		long count = taskMapper.updateMapByCriteria(
				MapUtils.put("dataVersion", dataVersion + 1).put("status", "0").getMap(), criteria);
		if (0 >= count)
			return false;
		return true;
	}

	@Override
	@Transactional
	public Object batchEdit(List<RcvRejectLinesDTO> rcvRejectLinesDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		for (RcvRejectLinesDTO rcvRejectLinesDTO : rcvRejectLinesDTOList) {
			RcvRejectLines rcvRejectLines = new RcvRejectLines();
			BeanUtils.copyProperties(rcvRejectLinesDTO, rcvRejectLines);
			this.vaildateModel(rcvRejectLines, true, userDTO);
			this.buildField(rcvRejectLines, true, userDTO, now);
			this.mapper.updateWithValidate(rcvRejectLines,
					p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
		}
		return "";
	}

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

	@Override
	public RcvRejectLinesDTO findByPkId(String pkId) {
		// TODO
		RcvRejectLines rcvRejectLines = this.findById(pkId);
		AssertUtils.notNull(rcvRejectLines, "model empty!");
		RcvRejectLinesDTO rcvRejectLinesDTO = new RcvRejectLinesDTO();
		BeanUtils.copyProperties(rcvRejectLines, rcvRejectLinesDTO);
		return rcvRejectLinesDTO;
	}

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

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

	private void buildField(RcvRejectLines rcvRejectLines, Boolean editFlag, UserDTO userDTO, Date now) {
		this.setBaseSysField(rcvRejectLines, editFlag, userDTO, now);
		rcvRejectLines.setExecutorUser(userDTO.getId()); // 执行者
		vaildateModelRepeated(rcvRejectLines, editFlag, userDTO);
	}

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

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

	private Restriction buildCondition(RcvRejectLinesDTO rcvRejectLinesDTO) {
		// TODO
		return null;
	}

	@Override
	public Page<TaskRejectedDetailDTO> extractTask(TaskQcDQueryVO taskQcDQueryVO, PageParam pageParam) {
		// TODO Auto-generated method stub
		TaskRejectedDetailDTO taskRejectedDetailDTO = new TaskRejectedDetailDTO();
		BeanUtils.copyProperties(taskQcDQueryVO, taskRejectedDetailDTO);
		return taskRejectedDetailService.findList(taskRejectedDetailDTO, pageParam);
	}

	@Override
	public Page<RcvHDTO> extractRcvHAndPro(RcvQueryVO rcvQueryVO, PageParam pageParam) {
		return taskRejectedDetailService.extractRcvHWithNativeSql(rcvQueryVO, pageParam);
	}

	@Override
	public Page<TaskRejectedDetailDTO> extractTask(TaskQueryVO queryVO, PageParam pageParam) {
		// 提取任务池中任务
		queryVO.setStatus("1"); // 能执行的任务
		return taskRejectedDetailService.extractTaskWithNativeSql(queryVO, pageParam);
	}

}
