/**
 * BladeX Commercial License Agreement
 * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
 * <p>
 * Use of this software is governed by the Commercial License Agreement
 * obtained after purchasing a license from BladeX.
 * <p>
 * 1. This software is for development use only under a valid license
 * from BladeX.
 * <p>
 * 2. Redistribution of this software's source code to any third party
 * without a commercial license is strictly prohibited.
 * <p>
 * 3. Licensees may copyright their own code but cannot use segments
 * from this software for such purposes. Copyright of this software
 * remains with BladeX.
 * <p>
 * Using this software signifies agreement to this License, and the software
 * must not be used for illegal purposes.
 * <p>
 * Author: Chill Zhuang (bladejava@qq.com)
 */
package org.springblade.transport.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.UserCache;
import org.springblade.system.pojo.entity.Dept;
import org.springblade.transport.excel.ShippingTemplateExcel;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.springblade.transport.mapper.ShippingTemplateMapper;
import org.springblade.transport.pojo.entity.ShippingTemplate;
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
import org.springblade.transport.pojo.vo.ShippingTemplateVO;
import org.springblade.transport.service.IShippingTemplateService;
import org.springblade.transport.support.TransportBusinessSupport;
import org.springblade.transport.wrapper.ShippingTemplateWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 发货模板 服务实现类
 *
 * @author Chill
 */
@Service
public class ShippingTemplateServiceImpl extends BaseServiceImpl<ShippingTemplateMapper, ShippingTemplate> implements IShippingTemplateService {

	@Override
	public IPage<ShippingTemplateVO> selectShippingTemplatePage(IPage<ShippingTemplate> page, ShippingTemplateVO shippingTemplate) {
		IPage<ShippingTemplate> entityPage = page(page, buildQuery(shippingTemplate));
		return ShippingTemplateWrapper.build().pageVO(entityPage);
	}

	@Override
	public ShippingTemplateVO detail(Long id) {
		return ShippingTemplateWrapper.build().entityVO(loadEditable(id, false));
	}

	@Override
	public String nextTemplateCode() {
		return nextCode();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submit(ShippingTemplate shippingTemplate) {
		boolean created = Func.isEmpty(shippingTemplate.getId());
		if (!created) {
			ShippingTemplate oldRecord = loadEditable(shippingTemplate.getId(), true);
			shippingTemplate.setTemplateCode(oldRecord.getTemplateCode());
			shippingTemplate.setDeptId(oldRecord.getDeptId());
			shippingTemplate.setDeptName(oldRecord.getDeptName());
		}
		prepare(shippingTemplate);
		if (created) {
			shippingTemplate.setTemplateCode(nextTemplateCode());
		}
		validate(shippingTemplate);
		return saveOrUpdate(shippingTemplate);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public BusinessRemoveResultVO removeShippingTemplate(String ids) {
		List<Long> idList = Func.toLongList(ids);
		if (Func.isEmpty(idList)) {
			throw new ServiceException("请选择需要删除的数据");
		}
		BusinessRemoveResultVO result = new BusinessRemoveResultVO();
		List<Long> deleteIdList = new ArrayList<>();
		for (ShippingTemplate shippingTemplate : listByIds(idList)) {
			TransportBusinessSupport.assertCurrentDept(shippingTemplate.getDeptId(), "发货模板");
			if (shouldSkipDelete(shippingTemplate)) {
				result.setSkippedCount(result.getSkippedCount() + 1);
				result.getSkippedCodes().add(shippingTemplate.getTemplateCode());
				continue;
			}
			deleteIdList.add(shippingTemplate.getId());
		}
		if (Func.isNotEmpty(deleteIdList)) {
			deleteLogic(deleteIdList);
		}
		result.setSuccessCount(deleteIdList.size());
		return result;
	}

	@Override
	public List<ShippingTemplateExcel> exportShippingTemplate(ShippingTemplateVO shippingTemplate, String ids) {
		LambdaQueryWrapper<ShippingTemplate> queryWrapper = buildQuery(shippingTemplate);
		if (Func.isNotEmpty(ids)) {
			queryWrapper.in(ShippingTemplate::getId, Func.toLongList(ids));
		}
		return list(queryWrapper).stream().map(record -> {
			ShippingTemplateExcel excel = new ShippingTemplateExcel();
			BeanUtil.copyProperties(record, excel);
			excel.setCreateUserName(UserCache.getUserRealName(record.getCreateUser()));
			excel.setUpdateUserName(UserCache.getUserRealName(record.getUpdateUser()));
			return excel;
		}).toList();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public ShippingTemplateVO copy(Long id) {
		ShippingTemplate source = loadEditable(id, true);
		ShippingTemplate target = new ShippingTemplate();
		target.setTemplateName(source.getTemplateName());
		target.setTemplateType(source.getTemplateType());
		target.setProjectId(source.getProjectId());
		target.setProjectName(source.getProjectName());
		target.setContractId(source.getContractId());
		target.setContractName(source.getContractName());
		target.setTransportType(source.getTransportType());
		target.setDepartureAddressId(source.getDepartureAddressId());
		target.setDepartureName(source.getDepartureName());
		target.setDepartureAddress(source.getDepartureAddress());
		target.setDepartureContact(source.getDepartureContact());
		target.setDeparturePhone(source.getDeparturePhone());
		target.setArrivalAddressId(source.getArrivalAddressId());
		target.setArrivalName(source.getArrivalName());
		target.setArrivalAddress(source.getArrivalAddress());
		target.setArrivalContact(source.getArrivalContact());
		target.setArrivalPhone(source.getArrivalPhone());
		target.setGoodsJson(source.getGoodsJson());
		target.setFreightJson(source.getFreightJson());
		target.setAttachmentsJson(source.getAttachmentsJson());
		target.setRemark(source.getRemark());
		target.setTemplateName(source.getTemplateName() + " - 副本");
		target.setTemplateCode(nextCode());
		prepare(target);
		validate(target);
		save(target);
		return detail(target.getId());
	}

	private LambdaQueryWrapper<ShippingTemplate> buildQuery(ShippingTemplateVO shippingTemplate) {
		TransportBusinessSupport.validateAllDept(shippingTemplate.getAllDept(), "发货模板");
		LambdaQueryWrapper<ShippingTemplate> queryWrapper = Wrappers.<ShippingTemplate>lambdaQuery().eq(ShippingTemplate::getIsDeleted, 0);
		if (!Objects.equals(shippingTemplate.getAllDept(), 1)) {
			queryWrapper.eq(ShippingTemplate::getDeptId, TransportBusinessSupport.currentDeptId("发货模板"));
		} else if (Func.isNotEmpty(shippingTemplate.getDeptId())) {
			queryWrapper.eq(ShippingTemplate::getDeptId, shippingTemplate.getDeptId());
		}
		if (Func.isNotEmpty(shippingTemplate.getTemplateCode())) {
			queryWrapper.eq(ShippingTemplate::getTemplateCode, shippingTemplate.getTemplateCode());
		}
		if (Func.isNotEmpty(shippingTemplate.getTemplateName())) {
			queryWrapper.like(ShippingTemplate::getTemplateName, shippingTemplate.getTemplateName());
		}
		if (Func.isNotEmpty(shippingTemplate.getTemplateType())) {
			queryWrapper.eq(ShippingTemplate::getTemplateType, shippingTemplate.getTemplateType());
		}
		if (Func.isNotEmpty(shippingTemplate.getProjectName())) {
			queryWrapper.like(ShippingTemplate::getProjectName, shippingTemplate.getProjectName());
		}
		if (Func.isNotEmpty(shippingTemplate.getContractName())) {
			queryWrapper.like(ShippingTemplate::getContractName, shippingTemplate.getContractName());
		}
		if (Func.isNotEmpty(shippingTemplate.getTransportType())) {
			queryWrapper.eq(ShippingTemplate::getTransportType, shippingTemplate.getTransportType());
		}
		if (Func.isNotEmpty(shippingTemplate.getDepartureName())) {
			queryWrapper.like(ShippingTemplate::getDepartureName, shippingTemplate.getDepartureName());
		}
		if (Func.isNotEmpty(shippingTemplate.getDepartureAddress())) {
			queryWrapper.like(ShippingTemplate::getDepartureAddress, shippingTemplate.getDepartureAddress());
		}
		if (Func.isNotEmpty(shippingTemplate.getDepartureContact())) {
			queryWrapper.like(ShippingTemplate::getDepartureContact, shippingTemplate.getDepartureContact());
		}
		if (Func.isNotEmpty(shippingTemplate.getDeparturePhone())) {
			queryWrapper.like(ShippingTemplate::getDeparturePhone, shippingTemplate.getDeparturePhone());
		}
		if (Func.isNotEmpty(shippingTemplate.getArrivalName())) {
			queryWrapper.like(ShippingTemplate::getArrivalName, shippingTemplate.getArrivalName());
		}
		if (Func.isNotEmpty(shippingTemplate.getArrivalAddress())) {
			queryWrapper.like(ShippingTemplate::getArrivalAddress, shippingTemplate.getArrivalAddress());
		}
		if (Func.isNotEmpty(shippingTemplate.getArrivalContact())) {
			queryWrapper.like(ShippingTemplate::getArrivalContact, shippingTemplate.getArrivalContact());
		}
		if (Func.isNotEmpty(shippingTemplate.getArrivalPhone())) {
			queryWrapper.like(ShippingTemplate::getArrivalPhone, shippingTemplate.getArrivalPhone());
		}
		if (Func.isNotEmpty(shippingTemplate.getRemark())) {
			queryWrapper.like(ShippingTemplate::getRemark, shippingTemplate.getRemark());
		}
		queryWrapper.orderByDesc(ShippingTemplate::getCreateTime);
		return queryWrapper;
	}

	private void prepare(ShippingTemplate shippingTemplate) {
		shippingTemplate.setTemplateCode(TransportBusinessSupport.trimToNull(shippingTemplate.getTemplateCode()));
		shippingTemplate.setTemplateName(TransportBusinessSupport.trimToNull(shippingTemplate.getTemplateName()));
		shippingTemplate.setTemplateType(TransportBusinessSupport.trimToNull(shippingTemplate.getTemplateType()));
		shippingTemplate.setProjectName(TransportBusinessSupport.trimToNull(shippingTemplate.getProjectName()));
		shippingTemplate.setContractName(TransportBusinessSupport.trimToNull(shippingTemplate.getContractName()));
		shippingTemplate.setTransportType(TransportBusinessSupport.trimToNull(shippingTemplate.getTransportType()));
		shippingTemplate.setDepartureName(TransportBusinessSupport.trimToNull(shippingTemplate.getDepartureName()));
		shippingTemplate.setDepartureAddress(TransportBusinessSupport.trimToNull(shippingTemplate.getDepartureAddress()));
		shippingTemplate.setDepartureContact(TransportBusinessSupport.trimToNull(shippingTemplate.getDepartureContact()));
		shippingTemplate.setDeparturePhone(TransportBusinessSupport.trimToNull(shippingTemplate.getDeparturePhone()));
		shippingTemplate.setArrivalName(TransportBusinessSupport.trimToNull(shippingTemplate.getArrivalName()));
		shippingTemplate.setArrivalAddress(TransportBusinessSupport.trimToNull(shippingTemplate.getArrivalAddress()));
		shippingTemplate.setArrivalContact(TransportBusinessSupport.trimToNull(shippingTemplate.getArrivalContact()));
		shippingTemplate.setArrivalPhone(TransportBusinessSupport.trimToNull(shippingTemplate.getArrivalPhone()));
		shippingTemplate.setGoodsJson(TransportBusinessSupport.trimToNull(shippingTemplate.getGoodsJson()));
		shippingTemplate.setFreightJson(TransportBusinessSupport.trimToNull(shippingTemplate.getFreightJson()));
		shippingTemplate.setAttachmentsJson(TransportBusinessSupport.trimToNull(shippingTemplate.getAttachmentsJson()));
		shippingTemplate.setDeptName(TransportBusinessSupport.trimToNull(shippingTemplate.getDeptName()));
		shippingTemplate.setRemark(TransportBusinessSupport.trimToNull(shippingTemplate.getRemark()));
		if (Func.isEmpty(shippingTemplate.getDeptId())) {
			Dept dept = TransportBusinessSupport.currentDept("发货模板");
			shippingTemplate.setDeptId(dept.getId());
			shippingTemplate.setDeptName(dept.getDeptName());
		}
		if (shippingTemplate.getStatus() == null) { shippingTemplate.setStatus(1); }
	}

	private void validate(ShippingTemplate shippingTemplate) {
		TransportBusinessSupport.validateRequired(shippingTemplate.getTemplateName(), "模板名称不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getTemplateType(), "模板类型不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getProjectName(), "项目不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getContractName(), "客户合同不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getTransportType(), "运输类型不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getDepartureAddress(), "发货地址不能为空");
		TransportBusinessSupport.validateRequired(shippingTemplate.getArrivalAddress(), "收货地址不能为空");
		TransportBusinessSupport.validateLength(shippingTemplate.getTemplateCode(), 255, "模板编号不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getTemplateName(), 255, "模板名称不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getTemplateType(), 255, "模板类型不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getProjectName(), 255, "项目不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getContractName(), 255, "客户合同不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getTransportType(), 255, "运输类型不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getDepartureName(), 255, "发货地不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getDepartureAddress(), 255, "发货地址不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getDepartureContact(), 255, "发货联系人不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getDeparturePhone(), 255, "发货联系方式不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getArrivalName(), 255, "收货地不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getArrivalAddress(), 255, "收货地址不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getArrivalContact(), 255, "收货联系人不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getArrivalPhone(), 255, "收货联系方式不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getGoodsJson(), 8000, "货物信息不能超过8000字");
		TransportBusinessSupport.validateLength(shippingTemplate.getFreightJson(), 8000, "运费信息不能超过8000字");
		TransportBusinessSupport.validateLength(shippingTemplate.getAttachmentsJson(), 8000, "附件不能超过8000字");
		TransportBusinessSupport.validateLength(shippingTemplate.getDeptName(), 255, "所属组织不能超过255字");
		TransportBusinessSupport.validateLength(shippingTemplate.getRemark(), 500, "备注不能超过500字");
	}

	private ShippingTemplate loadEditable(Long id, boolean checkDept) {
		if (Func.isEmpty(id)) {
			throw new ServiceException("主键不能为空");
		}
		ShippingTemplate shippingTemplate = getById(id);
		if (Func.isEmpty(shippingTemplate) || Objects.equals(shippingTemplate.getIsDeleted(), 1)) {
			throw new ServiceException("发货模板不存在");
		}
		if (checkDept) {
			TransportBusinessSupport.assertCurrentDept(shippingTemplate.getDeptId(), "发货模板");
		}
		return shippingTemplate;
	}

	private boolean shouldSkipDelete(ShippingTemplate shippingTemplate) {
		return false;
	}

	private synchronized String nextCode() {
		String prefix = "MBJH-" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
		List<ShippingTemplate> latestList = list(Wrappers.<ShippingTemplate>lambdaQuery()
			.select(ShippingTemplate::getTemplateCode)
			.likeRight(ShippingTemplate::getTemplateCode, prefix)
			.orderByDesc(ShippingTemplate::getTemplateCode)
			.last("LIMIT 1"));
		int next = 1;
		if (Func.isNotEmpty(latestList) && Func.isNotEmpty(latestList.get(0).getTemplateCode())) {
			String serial = latestList.get(0).getTemplateCode().substring(prefix.length());
			if (serial.chars().allMatch(Character::isDigit)) {
				next = Integer.parseInt(serial) + 1;
			}
		}
		return prefix + String.format("%03d", next);
	}

}
