/**
 * 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.CommonRouteExcel;
import org.springblade.transport.excel.CommonRouteImportExcel;
import org.springblade.transport.mapper.CommonRouteMapper;
import org.springblade.transport.pojo.entity.CommonRoute;
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
import org.springblade.transport.pojo.vo.CommonRouteVO;
import org.springblade.transport.service.ICommonRouteService;
import org.springblade.transport.support.TransportBusinessSupport;
import org.springblade.transport.wrapper.CommonRouteWrapper;
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 CommonRouteServiceImpl extends BaseServiceImpl<CommonRouteMapper, CommonRoute> implements ICommonRouteService {

	@Override
	public IPage<CommonRouteVO> selectCommonRoutePage(IPage<CommonRoute> page, CommonRouteVO commonRoute) {
		IPage<CommonRoute> entityPage = page(page, buildQuery(commonRoute));
		return CommonRouteWrapper.build().pageVO(entityPage);
	}

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

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submit(CommonRoute commonRoute) {
		boolean created = Func.isEmpty(commonRoute.getId());
		if (!created) {
			CommonRoute oldRecord = loadEditable(commonRoute.getId(), true);
			commonRoute.setRouteCode(oldRecord.getRouteCode());
			commonRoute.setDeptId(oldRecord.getDeptId());
			commonRoute.setDeptName(oldRecord.getDeptName());
		}
		prepare(commonRoute);
		if (created && Func.isEmpty(commonRoute.getRouteCode())) {
			commonRoute.setRouteCode(nextCode());
		}
		validate(commonRoute);
		return saveOrUpdate(commonRoute);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public BusinessRemoveResultVO removeCommonRoute(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 (CommonRoute commonRoute : listByIds(idList)) {
			TransportBusinessSupport.assertCurrentDept(commonRoute.getDeptId(), "常用线路");
			if (shouldSkipDelete(commonRoute)) {
				result.setSkippedCount(result.getSkippedCount() + 1);
				result.getSkippedCodes().add(commonRoute.getRouteCode());
				continue;
			}
			deleteIdList.add(commonRoute.getId());
		}
		if (Func.isNotEmpty(deleteIdList)) {
			deleteLogic(deleteIdList);
		}
		result.setSuccessCount(deleteIdList.size());
		return result;
	}

	@Override
	public List<CommonRouteExcel> exportCommonRoute(CommonRouteVO commonRoute, String ids) {
		LambdaQueryWrapper<CommonRoute> queryWrapper = buildQuery(commonRoute);
		if (Func.isNotEmpty(ids)) {
			queryWrapper.in(CommonRoute::getId, Func.toLongList(ids));
		}
		return list(queryWrapper).stream().map(record -> {
			CommonRouteExcel excel = new CommonRouteExcel();
			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 List<CommonRouteImportExcel> importCommonRoute(List<CommonRouteImportExcel> data) {
		if (Func.isEmpty(data)) {
			throw new ServiceException("导入数据不能为空");
		}
		List<CommonRouteImportExcel> failureList = new ArrayList<>();
		for (int index = 0; index < data.size(); index++) {
			CommonRouteImportExcel excel = data.get(index);
			try {
				CommonRoute commonRoute = new CommonRoute();
				BeanUtil.copyProperties(excel, commonRoute);
				submit(commonRoute);
			} catch (Exception exception) {
				excel.setErrorMessage("第" + (index + 2) + "行：" + exception.getMessage());
				failureList.add(excel);
			}
		}
		return failureList;
	}

	private LambdaQueryWrapper<CommonRoute> buildQuery(CommonRouteVO commonRoute) {
		TransportBusinessSupport.validateAllDept(commonRoute.getAllDept(), "常用线路");
		LambdaQueryWrapper<CommonRoute> queryWrapper = Wrappers.<CommonRoute>lambdaQuery().eq(CommonRoute::getIsDeleted, 0);
		if (!Objects.equals(commonRoute.getAllDept(), 1)) {
			queryWrapper.eq(CommonRoute::getDeptId, TransportBusinessSupport.currentDeptId("常用线路"));
		} else if (Func.isNotEmpty(commonRoute.getDeptId())) {
			queryWrapper.eq(CommonRoute::getDeptId, commonRoute.getDeptId());
		}
		if (Func.isNotEmpty(commonRoute.getRouteCode())) {
			queryWrapper.eq(CommonRoute::getRouteCode, commonRoute.getRouteCode());
		}
		if (Func.isNotEmpty(commonRoute.getRouteName())) {
			queryWrapper.like(CommonRoute::getRouteName, commonRoute.getRouteName());
		}
		if (Func.isNotEmpty(commonRoute.getDepartureName())) {
			queryWrapper.like(CommonRoute::getDepartureName, commonRoute.getDepartureName());
		}
		if (Func.isNotEmpty(commonRoute.getDepartureAddress())) {
			queryWrapper.like(CommonRoute::getDepartureAddress, commonRoute.getDepartureAddress());
		}
		if (Func.isNotEmpty(commonRoute.getDepartureContact())) {
			queryWrapper.like(CommonRoute::getDepartureContact, commonRoute.getDepartureContact());
		}
		if (Func.isNotEmpty(commonRoute.getDeparturePhone())) {
			queryWrapper.like(CommonRoute::getDeparturePhone, commonRoute.getDeparturePhone());
		}
		if (Func.isNotEmpty(commonRoute.getArrivalName())) {
			queryWrapper.like(CommonRoute::getArrivalName, commonRoute.getArrivalName());
		}
		if (Func.isNotEmpty(commonRoute.getArrivalAddress())) {
			queryWrapper.like(CommonRoute::getArrivalAddress, commonRoute.getArrivalAddress());
		}
		if (Func.isNotEmpty(commonRoute.getArrivalContact())) {
			queryWrapper.like(CommonRoute::getArrivalContact, commonRoute.getArrivalContact());
		}
		if (Func.isNotEmpty(commonRoute.getArrivalPhone())) {
			queryWrapper.like(CommonRoute::getArrivalPhone, commonRoute.getArrivalPhone());
		}
		if (Func.isNotEmpty(commonRoute.getRemark())) {
			queryWrapper.like(CommonRoute::getRemark, commonRoute.getRemark());
		}
		queryWrapper.orderByDesc(CommonRoute::getUpdateTime).orderByDesc(CommonRoute::getCreateTime);
		return queryWrapper;
	}

	private void prepare(CommonRoute commonRoute) {
		commonRoute.setRouteCode(TransportBusinessSupport.trimToNull(commonRoute.getRouteCode()));
		commonRoute.setRouteName(TransportBusinessSupport.trimToNull(commonRoute.getRouteName()));
		commonRoute.setDepartureName(TransportBusinessSupport.trimToNull(commonRoute.getDepartureName()));
		commonRoute.setDepartureAddress(TransportBusinessSupport.trimToNull(commonRoute.getDepartureAddress()));
		commonRoute.setDepartureContact(TransportBusinessSupport.trimToNull(commonRoute.getDepartureContact()));
		commonRoute.setDeparturePhone(TransportBusinessSupport.trimToNull(commonRoute.getDeparturePhone()));
		commonRoute.setArrivalName(TransportBusinessSupport.trimToNull(commonRoute.getArrivalName()));
		commonRoute.setArrivalAddress(TransportBusinessSupport.trimToNull(commonRoute.getArrivalAddress()));
		commonRoute.setArrivalContact(TransportBusinessSupport.trimToNull(commonRoute.getArrivalContact()));
		commonRoute.setArrivalPhone(TransportBusinessSupport.trimToNull(commonRoute.getArrivalPhone()));
		commonRoute.setDeptName(TransportBusinessSupport.trimToNull(commonRoute.getDeptName()));
		commonRoute.setRemark(TransportBusinessSupport.trimToNull(commonRoute.getRemark()));
		if (Func.isEmpty(commonRoute.getDeptId())) {
			Dept dept = TransportBusinessSupport.currentDept("常用线路");
			commonRoute.setDeptId(dept.getId());
			commonRoute.setDeptName(dept.getDeptName());
		}
		if (commonRoute.getStatus() == null) { commonRoute.setStatus(1); }
	}

	private void validate(CommonRoute commonRoute) {
		TransportBusinessSupport.validateRequired(commonRoute.getRouteName(), "线路名称不能为空");
		TransportBusinessSupport.validateRequired(commonRoute.getDepartureName(), "发货地不能为空");
		TransportBusinessSupport.validateRequired(commonRoute.getDepartureAddress(), "发货地址不能为空");
		TransportBusinessSupport.validateRequired(commonRoute.getArrivalName(), "收货地不能为空");
		TransportBusinessSupport.validateRequired(commonRoute.getArrivalAddress(), "收货地址不能为空");
		validateRouteNameUnique(commonRoute);
		validateAddressCombinationUnique(commonRoute);
		TransportBusinessSupport.validateLength(commonRoute.getRouteCode(), 255, "线路编号不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getRouteName(), 255, "线路名称不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getDepartureName(), 255, "发货地不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getDepartureAddress(), 255, "发货地址不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getDepartureContact(), 255, "发货联系人不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getDeparturePhone(), 255, "发货联系方式不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getArrivalName(), 255, "收货地不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getArrivalAddress(), 255, "收货地址不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getArrivalContact(), 255, "收货联系人不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getArrivalPhone(), 255, "收货联系方式不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getDeptName(), 255, "所属组织不能超过255字");
		TransportBusinessSupport.validateLength(commonRoute.getRemark(), 500, "备注不能超过500字");
		TransportBusinessSupport.validatePhone(commonRoute.getDeparturePhone(), "发货联系方式格式不正确");
		TransportBusinessSupport.validatePhone(commonRoute.getArrivalPhone(), "收货联系方式格式不正确");
		TransportBusinessSupport.validateCoordinate(commonRoute.getDepartureLongitude(), true);
		TransportBusinessSupport.validateCoordinate(commonRoute.getDepartureLatitude(), false);
		TransportBusinessSupport.validateCoordinate(commonRoute.getArrivalLongitude(), true);
		TransportBusinessSupport.validateCoordinate(commonRoute.getArrivalLatitude(), false);
	}

	private void validateRouteNameUnique(CommonRoute commonRoute) {
		LambdaQueryWrapper<CommonRoute> queryWrapper = Wrappers.<CommonRoute>lambdaQuery()
			.eq(CommonRoute::getIsDeleted, 0)
			.eq(CommonRoute::getDeptId, commonRoute.getDeptId())
			.eq(CommonRoute::getRouteName, commonRoute.getRouteName());
		if (Func.isNotEmpty(commonRoute.getId())) {
			queryWrapper.ne(CommonRoute::getId, commonRoute.getId());
		}
		if (count(queryWrapper) > 0) {
			throw new ServiceException("线路名称已存在");
		}
	}

	private void validateAddressCombinationUnique(CommonRoute commonRoute) {
		LambdaQueryWrapper<CommonRoute> queryWrapper = Wrappers.<CommonRoute>lambdaQuery()
			.eq(CommonRoute::getIsDeleted, 0)
			.eq(CommonRoute::getDeptId, commonRoute.getDeptId())
			.eq(CommonRoute::getDepartureAddress, commonRoute.getDepartureAddress())
			.eq(CommonRoute::getArrivalAddress, commonRoute.getArrivalAddress());
		if (Func.isNotEmpty(commonRoute.getId())) {
			queryWrapper.ne(CommonRoute::getId, commonRoute.getId());
		}
		if (count(queryWrapper) > 0) {
			throw new ServiceException("相同的发货地址和收货地址组合已存在");
		}
	}

	private CommonRoute loadEditable(Long id, boolean checkDept) {
		if (Func.isEmpty(id)) {
			throw new ServiceException("主键不能为空");
		}
		CommonRoute commonRoute = getById(id);
		if (Func.isEmpty(commonRoute) || Objects.equals(commonRoute.getIsDeleted(), 1)) {
			throw new ServiceException("常用线路不存在");
		}
		if (checkDept) {
			TransportBusinessSupport.assertCurrentDept(commonRoute.getDeptId(), "常用线路");
		}
		return commonRoute;
	}

	private boolean shouldSkipDelete(CommonRoute commonRoute) {
		return false;
	}

	private synchronized String nextCode() {
		String prefix = "XL";
		List<CommonRoute> latestList = list(Wrappers.<CommonRoute>lambdaQuery()
			.select(CommonRoute::getRouteCode)
			.likeRight(CommonRoute::getRouteCode, prefix)
			.orderByDesc(CommonRoute::getRouteCode)
			.last("LIMIT 1"));
		int next = 1;
		if (Func.isNotEmpty(latestList) && Func.isNotEmpty(latestList.get(0).getRouteCode())) {
			String serial = latestList.get(0).getRouteCode().substring(prefix.length());
			if (serial.chars().allMatch(Character::isDigit)) {
				next = Integer.parseInt(serial) + 1;
			}
		}
		return prefix + String.format("%05d", next);
	}

}
