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

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.rcv.RcvLinesPicMapper;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.rcv.RcvLinesPicDTO;
import com.prolog.cs.biz.inbound.model.rcv.RcvLinesPic;
import com.prolog.cs.biz.inbound.service.rcv.RcvLinesPicService;
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.exception.SaveException;
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.DaoUtils;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.AssertUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 RcvLinesPicServiceImpl implements RcvLinesPicService {

	@Resource
	private RcvLinesPicMapper mapper;

	@Resource
	private UserUtils userUtils;

	private static Logger logger = LoggerFactory.getLogger(RcvLinesPicServiceImpl.class);

	@Override
	public Object add(RcvLinesPicDTO rcvLinesPicDTO) {
		// TODO vaildate
		UserDTO userDTO = userUtils.getUserDTO();
		this.vaildateModel(rcvLinesPicDTO, false, userDTO, 0);
		RcvLinesPic rcvLinesPic = new RcvLinesPic();
		BeanUtils.copyProperties(rcvLinesPicDTO, rcvLinesPic);
		this.buildField(rcvLinesPic, false, userDTO);
		this.mapper.save(rcvLinesPic);
		return true;
	}

	@Override
	public Object edit(String pkId, RcvLinesPicDTO rcvLinesPicDTO) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		this.vaildateModel(rcvLinesPicDTO, false, userDTO, 0);
		if (canEdit(rcvLinesPicDTO.getRcvHeaderPicId())) {
			RcvLinesPic rcvLinesPic = new RcvLinesPic();
			BeanUtils.copyProperties(rcvLinesPicDTO, rcvLinesPic);
			this.buildField(rcvLinesPic, false, userDTO);
			this.mapper.updateWithValidate(rcvLinesPic,
					p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
			return true;
		}
		return false;
	}

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

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

	@Override
	public Page<RcvLinesPicDTO> findList(RcvLinesPicDTO rcvLinesPicDTO, PageParam pageParam) {
		Criteria criteria = Criteria.forClass(RcvLinesPic.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();
			RcvLinesPicDTO condition = rcvLinesPicDTO;
			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<RcvLinesPic> list = this.mapper.findByCriteria(criteria);
		List<RcvLinesPicDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
			RcvLinesPicDTO target = new RcvLinesPicDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		}).collect(Collectors.toList());
		Page<RcvLinesPic> page = PageUtils.getPage(list);
		Page<RcvLinesPicDTO> 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<RcvLinesPicDTO> rcvLinesPicDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		int row = 0;
		for (RcvLinesPicDTO rcvLinesPicDTO : rcvLinesPicDTOList) {
			row++;
			this.vaildateModel(rcvLinesPicDTO, false, userDTO, row);
			RcvLinesPic rcvLinesPic = new RcvLinesPic();
			BeanUtils.copyProperties(rcvLinesPicDTO, rcvLinesPic);
			this.buildField(rcvLinesPic, false, userDTO, now);
			this.mapper.save(rcvLinesPic);
		}
		return true;
	}

	@Override
	@Transactional
	public Object batchEdit(List<RcvLinesPicDTO> rcvLinesPicDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		int row = 0;
		for (RcvLinesPicDTO rcvLinesPicDTO : rcvLinesPicDTOList) {
			// 是否可编辑校验
			this.vaildateModel(rcvLinesPicDTO, false, userDTO, row);
			RcvLinesPic rcvLinesPic = new RcvLinesPic();
			BeanUtils.copyProperties(rcvLinesPicDTO, rcvLinesPic);
			this.buildField(rcvLinesPic, true, userDTO, now);
			this.mapper.updateWithValidate(rcvLinesPic,
					p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
		}
		return true;
	}

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

	@Override
	public RcvLinesPicDTO findByPkId(String pkId) {
		// TODO
		RcvLinesPic rcvLinesPic = this.findById(pkId);
		AssertUtils.notNull(rcvLinesPic, "model empty!");
		RcvLinesPicDTO rcvLinesPicDTO = new RcvLinesPicDTO();
		BeanUtils.copyProperties(rcvLinesPic, rcvLinesPicDTO);
		return rcvLinesPicDTO;
	}

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

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

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

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

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

	private Restriction buildCondition(RcvLinesPicDTO rcvLinesPicDTO) {

		return Restrictions.eq("rcvLineId", rcvLinesPicDTO.getRcvLineId());
	}

	@Override
	@Transactional
	public Object batchAdd(List<RcvLinesPicDTO> rcvLinesPicDTOList, String rcvLineId, UserDTO userDTO) {
		// 批量添加
		if (null == userDTO)
			userDTO = userUtils.getUserDTO();
		int row = 0;
		boolean editFlag = Boolean.FALSE;
		Date now = new Date();
		List<RcvLinesPic> result = new ArrayList<>();
		for (RcvLinesPicDTO rcvLinesPicDTO : rcvLinesPicDTOList) {
			row++;
			// TODO 这里后期判断是否是更新或者更新
			// 头表id
			rcvLinesPicDTO.setRcvHeaderId(rcvLineId);
			this.buildDefaultField(rcvLinesPicDTO, editFlag, userDTO);
			this.vaildateModel(rcvLinesPicDTO, editFlag, userDTO, row);
			RcvLinesPic pic = new RcvLinesPic();
			BeanUtils.copyProperties(rcvLinesPicDTO, pic);
			this.buildField(pic, editFlag, userDTO, now);
			result.add(pic);
//			this.mapper.save(pic);
		}
		if (result.size() > 500) {
			try {
				DaoUtils.saveBatch(this.mapper, result, 500);
			} catch (Exception e) {
				logger.error("RcvLinesPicServiceImpl 错误详情:", e);
				throw new SaveException("批量保存收据行图片数据库失败!");
			}
		} else {
			this.mapper.saveBatch(result);
		}

		return true;
	}

	private void buildField(RcvLinesPic pic, boolean editFlag, UserDTO userDTO, Date now) {
		// 构建基础系统字段
		Date gmtCreate = pic.getGmtCreate();
		Date gmtModified = pic.getGmtModified();
		String creator = pic.getCreator();
		String creatorName = pic.getCreatorName();
		String modifier = pic.getModifier();
		String modifierName = pic.getModifierName();

		String id = userDTO.getId();
		String enterpriseId = userDTO.getEnterpriseId();
		String username = userDTO.getUsername();
		if (null == now)
			now = new Date();
		if (!editFlag) {
			if (ObjectUtils.isNull(creator))
				pic.setCreator(id);
			if (ObjectUtils.isNull(creatorName))
				pic.setCreatorName(username);
			if (ObjectUtils.isNull(gmtCreate))
				pic.setGmtCreate(now);
			if (ObjectUtils.isNull(enterpriseId))
				pic.setEntId(enterpriseId);
		}
		if (ObjectUtils.isNull(modifier))
			pic.setModifier(id);
		if (ObjectUtils.isNull(modifierName))
			pic.setModifierName(username);
		if (ObjectUtils.isNull(gmtModified))
			pic.setGmtModified(now);
		vaildateModelRepeated(pic, editFlag, userDTO);
	}

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

	}

	private void vaildateModel(RcvLinesPicDTO rcvLinesPicDTO, boolean editFlag, UserDTO userDTO, int row) {
		// 校验数据
		Set<ConstraintViolation<RcvLinesPicDTO>> validate = null;
		if (!editFlag) {
			// 添加校验
			validate = validator.validate(rcvLinesPicDTO, validAdd.class);
		} else {
			validate = validator.validate(rcvLinesPicDTO, 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());
		}
	}

	@Resource
	private Validator validator;
}
