/**
 * 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>
 * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
 * not liable for any claims arising from secondary or illegal development.
 * <p>
 * Author: Chill Zhuang (bladejava@qq.com)
 */
package org.springblade.transport.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
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.transport.excel.TransportVehicleExcel;
import org.springblade.transport.mapper.TransportVehicleMapper;
import org.springblade.transport.pojo.entity.TransportVehicle;
import org.springblade.transport.pojo.vo.TransportVehicleExpiryStatVO;
import org.springblade.transport.pojo.vo.TransportVehicleVO;
import org.springblade.transport.service.ITransportVehicleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 车辆管理 服务实现类
 *
 * @author Chill
 */
@Service
public class TransportVehicleServiceImpl extends BaseServiceImpl<TransportVehicleMapper, TransportVehicle> implements ITransportVehicleService {

	private static final Pattern PLATE_NO_PATTERN = Pattern.compile("^[\\u4e00-\\u9fa5][A-Z][A-Z0-9挂学警港澳]{5,6}$");
	private static final int SHORT_TEXT_MAX_LENGTH = 50;
	private static final int ORG_MAX_LENGTH = 50;
	private static final int REMARK_MAX_LENGTH = 200;
	private static final int DEFAULT_ENABLED_STATUS = 1;
	private static final int DEFAULT_FALSE = 0;
	private static final int CERTIFICATION_PENDING = 0;
	private static final int CERTIFICATION_APPROVED = 1;
	private static final int CERTIFICATION_REJECTED = 2;

	@Override
	public IPage<TransportVehicleVO> selectTransportVehiclePage(IPage<TransportVehicleVO> page, TransportVehicleVO vehicle) {
		prepareQuery(vehicle);
		return page.setRecords(baseMapper.selectTransportVehiclePage(page, vehicle));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submit(TransportVehicle vehicle) {
		prepare(vehicle);
		validate(vehicle);
		checkUniquePlateNo(vehicle);
		vehicle.setCertificationStatus(CERTIFICATION_PENDING);
		vehicle.setCertificationRejectReason(null);
		return saveOrUpdate(vehicle);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean auditCertification(Long id, Integer certificationStatus, String rejectReason) {
		if (Func.isEmpty(id) || (certificationStatus != CERTIFICATION_APPROVED && certificationStatus != CERTIFICATION_REJECTED)) {
			throw new ServiceException("认证审核参数不正确");
		}
		String reason = trimToNull(rejectReason);
		if (certificationStatus == CERTIFICATION_REJECTED && Func.isEmpty(reason)) {
			throw new ServiceException("请输入认证驳回原因");
		}
		validateLength(reason, REMARK_MAX_LENGTH, "认证驳回原因不能超过200字");
		TransportVehicle vehicle = new TransportVehicle();
		vehicle.setId(id);
		vehicle.setCertificationStatus(certificationStatus);
		vehicle.setCertificationRejectReason(certificationStatus == CERTIFICATION_REJECTED ? reason : null);
		return updateById(vehicle);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean changeStatus(Long id, Integer status) {
		if (Func.isEmpty(id)) {
			throw new ServiceException("车辆主键不能为空");
		}
		if (Func.isEmpty(status) || (status != 1 && status != 2)) {
			throw new ServiceException("状态值不正确");
		}
		TransportVehicle vehicle = new TransportVehicle();
		vehicle.setId(id);
		vehicle.setStatus(status);
		return updateById(vehicle);
	}

	@Override
	public TransportVehicleExpiryStatVO expiryStat(TransportVehicleVO vehicle) {
		prepareQuery(vehicle);
		vehicle.setExpireStatus(null);
		TransportVehicleExpiryStatVO stat = baseMapper.selectExpiryStat(vehicle);
		if (stat == null) {
			stat = new TransportVehicleExpiryStatVO();
		}
		stat.setTotal(defaultZero(stat.getTotal()));
		stat.setWithin30(defaultZero(stat.getWithin30()));
		stat.setExpired(defaultZero(stat.getExpired()));
		return stat;
	}

	@Override
	public List<TransportVehicleExcel> exportTransportVehicle(Wrapper<TransportVehicle> queryWrapper) {
		return list(queryWrapper).stream().map(vehicle -> {
			TransportVehicleExcel excel = Objects.requireNonNull(BeanUtil.copyProperties(vehicle, TransportVehicleExcel.class));
			excel.setStatusName(vehicle.getStatus() != null && vehicle.getStatus() == 2 ? "停用" : "启用");
			return excel;
		}).toList();
	}

	private void prepareQuery(TransportVehicleVO vehicle) {
		if (vehicle.getToday() == null) {
			vehicle.setToday(LocalDate.now());
		}
		if (vehicle.getWarningDate() == null) {
			vehicle.setWarningDate(vehicle.getToday().plusDays(30));
		}
	}

	private void prepare(TransportVehicle vehicle) {
		vehicle.setOrganizationName(trimToEmpty(vehicle.getOrganizationName()));
		vehicle.setPlateNo(trimToEmpty(vehicle.getPlateNo()).toUpperCase());
		vehicle.setPlateColor(trimToNull(vehicle.getPlateColor()));
		vehicle.setVehicleType(trimToEmpty(vehicle.getVehicleType()));
		vehicle.setBusinessRelation(trimToEmpty(vehicle.getBusinessRelation()));
		vehicle.setEnergyType(trimToEmpty(vehicle.getEnergyType()));
		vehicle.setCustomsRecordNo(trimToNull(vehicle.getCustomsRecordNo()));
		vehicle.setDrivingLicenseNo(trimToEmpty(vehicle.getDrivingLicenseNo()));
		vehicle.setRoadTransportCertNo(trimToEmpty(vehicle.getRoadTransportCertNo()));
		vehicle.setRegistrationNo(trimToEmpty(vehicle.getRegistrationNo()));
		vehicle.setDrivingLicenseImage(trimToNull(vehicle.getDrivingLicenseImage()));
		vehicle.setDrivingLicenseMainBack(trimToNull(vehicle.getDrivingLicenseMainBack()));
		vehicle.setDrivingLicenseViceFront(trimToNull(vehicle.getDrivingLicenseViceFront()));
		vehicle.setDrivingLicenseViceBack(trimToNull(vehicle.getDrivingLicenseViceBack()));
		vehicle.setRoadTransportCertImage(trimToNull(vehicle.getRoadTransportCertImage()));
		vehicle.setRegistrationImage(trimToNull(vehicle.getRegistrationImage()));
		vehicle.setRemark(trimToNull(vehicle.getRemark()));
		if (vehicle.getCompulsoryScrapLongTerm() == null) {
			vehicle.setCompulsoryScrapLongTerm(DEFAULT_FALSE);
		}
		if (vehicle.getDrivingLicenseLongTerm() == null) {
			vehicle.setDrivingLicenseLongTerm(DEFAULT_FALSE);
		}
		if (vehicle.getRoadTransportCertLongTerm() == null) {
			vehicle.setRoadTransportCertLongTerm(DEFAULT_FALSE);
		}
		if (vehicle.getAnnualReviewLongTerm() == null) {
			vehicle.setAnnualReviewLongTerm(DEFAULT_FALSE);
		}
		if (vehicle.getStatus() == null) {
			vehicle.setStatus(DEFAULT_ENABLED_STATUS);
		}
	}

	private void validate(TransportVehicle vehicle) {
		if (Func.isEmpty(vehicle.getOrganizationName())) {
			throw new ServiceException("所属组织不能为空");
		}
		if (Func.isEmpty(vehicle.getPlateNo())) {
			throw new ServiceException("车牌号不能为空");
		}
		if (!PLATE_NO_PATTERN.matcher(vehicle.getPlateNo()).matches()) {
			throw new ServiceException("车牌号格式不正确");
		}
		if (Func.isEmpty(vehicle.getPlateColor())) {
			throw new ServiceException("车牌颜色不能为空");
		}
		if (Func.isEmpty(vehicle.getVehicleType())) {
			throw new ServiceException("车辆类型不能为空");
		}
		if (Func.isEmpty(vehicle.getApprovedLoadKg())) {
			throw new ServiceException("核定载质量不能为空");
		}
		if (Func.isEmpty(vehicle.getBusinessRelation())) {
			throw new ServiceException("业务关系不能为空");
		}
		if (Func.isEmpty(vehicle.getEnergyType())) {
			throw new ServiceException("能源类型不能为空");
		}
		if (Func.isEmpty(vehicle.getDrivingLicenseNo())) {
			throw new ServiceException("行驶证档案编号不能为空");
		}
		if (Func.isEmpty(vehicle.getDrivingLicenseEndDate())) {
			throw new ServiceException("行驶证有效期不能为空");
		}
		if (Func.isEmpty(vehicle.getRoadTransportCertNo())) {
			throw new ServiceException("道路运输证号不能为空");
		}
		if (Func.isEmpty(vehicle.getRoadTransportCertEndDate())) {
			throw new ServiceException("道路运输证有效期不能为空");
		}
		if (vehicle.getAnnualReviewLongTerm() != 1 && Func.isEmpty(vehicle.getAnnualReviewEndDate())) {
			throw new ServiceException("道路运输年审有效期不能为空");
		}
		if (Func.isEmpty(vehicle.getRegistrationNo())) {
			throw new ServiceException("机动车登记编号不能为空");
		}
		validateNonNegative(vehicle.getOuterLength(), "外廓长度不能小于0");
		validateNonNegative(vehicle.getOuterWidth(), "外廓宽度不能小于0");
		validateNonNegative(vehicle.getOuterHeight(), "外廓高度不能小于0");
		validateNonNegative(vehicle.getApprovedLoadKg(), "核定载质量不能小于0");
		validateNonNegative(vehicle.getTractionMassKg(), "准牵引总质量不能小于0");
		validateLength(vehicle.getOrganizationName(), ORG_MAX_LENGTH, "所属组织不能超过50字");
		validateLength(vehicle.getPlateColor(), SHORT_TEXT_MAX_LENGTH, "车牌颜色不能超过50字");
		validateLength(vehicle.getVehicleType(), SHORT_TEXT_MAX_LENGTH, "车辆类型不能超过50字");
		validateLength(vehicle.getBusinessRelation(), SHORT_TEXT_MAX_LENGTH, "业务关系不能超过50字");
		validateLength(vehicle.getEnergyType(), SHORT_TEXT_MAX_LENGTH, "能源类型不能超过50字");
		validateLength(vehicle.getCustomsRecordNo(), SHORT_TEXT_MAX_LENGTH, "海关备案号不能超过50字");
		validateLength(vehicle.getDrivingLicenseNo(), SHORT_TEXT_MAX_LENGTH, "行驶证档案编号不能超过50字");
		validateLength(vehicle.getRoadTransportCertNo(), SHORT_TEXT_MAX_LENGTH, "道路运输证号不能超过50字");
		validateLength(vehicle.getRegistrationNo(), SHORT_TEXT_MAX_LENGTH, "机动车登记编号不能超过50字");
		validateLength(vehicle.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字");
		validateDateRange(vehicle.getDrivingLicenseStartDate(), vehicle.getDrivingLicenseEndDate(), "行驶证有效期止不能早于有效期起");
		validateDateRange(vehicle.getRoadTransportCertStartDate(), vehicle.getRoadTransportCertEndDate(), "道路运输证有效期止不能早于有效期起");
	}

	private void checkUniquePlateNo(TransportVehicle vehicle) {
		Long count = count(Wrappers.<TransportVehicle>lambdaQuery()
			.eq(TransportVehicle::getIsDeleted, 0)
			.eq(TransportVehicle::getPlateNo, vehicle.getPlateNo())
			.ne(Func.isNotEmpty(vehicle.getId()), TransportVehicle::getId, vehicle.getId()));
		if (count > 0) {
			throw new ServiceException("车牌号已存在");
		}
	}

	private void validateNonNegative(Integer value, String message) {
		if (Func.isNotEmpty(value) && value < 0) {
			throw new ServiceException(message);
		}
	}

	private void validateLength(String value, int maxLength, String message) {
		if (Func.isNotEmpty(value) && value.length() > maxLength) {
			throw new ServiceException(message);
		}
	}

	private void validateDateRange(LocalDate startDate, LocalDate endDate, String message) {
		if (Func.isNotEmpty(startDate) && Func.isNotEmpty(endDate) && endDate.isBefore(startDate)) {
			throw new ServiceException(message);
		}
	}

	private Long defaultZero(Long value) {
		return value == null ? 0L : value;
	}

	private String trimToEmpty(String value) {
		return value == null ? "" : value.trim();
	}

	private String trimToNull(String value) {
		String trimValue = trimToEmpty(value);
		return trimValue.isEmpty() ? null : trimValue;
	}

}
