/**
 * 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.system.cache.UserCache;
import org.springblade.transport.excel.InsuranceRecordExcel;
import org.springblade.transport.excel.InsuranceRecordExportExcel;
import org.springblade.transport.mapper.InsuranceRecordMapper;
import org.springblade.transport.pojo.entity.InsuranceRecord;
import org.springblade.transport.pojo.vo.InsuranceRecordVO;
import org.springblade.transport.service.IInsuranceRecordService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 保险记录 服务实现类
 *
 * @author Chill
 */
@Service
public class InsuranceRecordServiceImpl extends BaseServiceImpl<InsuranceRecordMapper, InsuranceRecord> implements IInsuranceRecordService {

	private static final int VEHICLE_NO_MAX_LENGTH = 50;
	private static final int INSURANCE_TYPE_MAX_LENGTH = 50;
	private static final int POLICY_NO_MAX_LENGTH = 80;
	private static final int INVOICE_NO_MAX_LENGTH = 80;
	private static final int OCR_TEMPLATE_MAX_LENGTH = 100;
	private static final int POLICY_FILE_MAX_LENGTH = 1000;
	private static final int REMARK_MAX_LENGTH = 200;
	private static final Set<String> SUPPORT_FILE_TYPES = Set.of("jpg", "jpeg", "png", "pdf");

	@Override
	public IPage<InsuranceRecordVO> selectInsuranceRecordPage(IPage<InsuranceRecordVO> page, InsuranceRecordVO insuranceRecord) {
		List<InsuranceRecordVO> records = baseMapper.selectInsuranceRecordPage(page, insuranceRecord);
		records.forEach(record -> record.setUpdateUserName(UserCache.getUserRealName(record.getUpdateUser())));
		return page.setRecords(records);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submit(InsuranceRecord insuranceRecord) {
		prepare(insuranceRecord);
		validate(insuranceRecord);
		checkUniquePolicyNo(insuranceRecord);
		return saveOrUpdate(insuranceRecord);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public List<InsuranceRecordExcel> importInsuranceRecord(List<InsuranceRecordExcel> data) {
		if (Func.isEmpty(data)) {
			throw new ServiceException("导入数据不能为空");
		}
		List<InsuranceRecordExcel> errorList = new ArrayList<>();
		for (int index = 0; index < data.size(); index++) {
			InsuranceRecordExcel excel = data.get(index);
			try {
				InsuranceRecord insuranceRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, InsuranceRecord.class));
				submit(insuranceRecord);
			} catch (Exception exception) {
				excel.setErrorMessage("第" + (index + 2) + "行：" + exception.getMessage());
				errorList.add(excel);
			}
		}
		return errorList;
	}

	@Override
	public List<InsuranceRecordExportExcel> exportInsuranceRecord(Wrapper<InsuranceRecord> queryWrapper) {
		return list(queryWrapper).stream().map(insuranceRecord -> {
			InsuranceRecordExportExcel excel = Objects.requireNonNull(BeanUtil.copyProperties(insuranceRecord, InsuranceRecordExportExcel.class));
			excel.setInsuredAmount(nonNegative(insuranceRecord.getInsuredAmount()));
			excel.setPremium(nonNegative(insuranceRecord.getPremium()));
			excel.setUpdateUserName(UserCache.getUserRealName(insuranceRecord.getUpdateUser()));
			return excel;
		}).toList();
	}

	@Override
	public InsuranceRecord recognizePolicy(MultipartFile file, String vehicleType, String ocrTemplate) {
		validatePolicyFile(file);
		InsuranceRecord insuranceRecord = new InsuranceRecord();
		insuranceRecord.setVehicleType(normalizeVehicleType(vehicleType));
		insuranceRecord.setOcrTemplate(trimToNull(ocrTemplate));
		throw new ServiceException("当前未配置OCR识别服务，请手动填写保单信息");
	}

	private void prepare(InsuranceRecord insuranceRecord) {
		insuranceRecord.setVehicleType(normalizeVehicleType(insuranceRecord.getVehicleType()));
		insuranceRecord.setVehicleNo(trimToEmpty(insuranceRecord.getVehicleNo()).toUpperCase());
		insuranceRecord.setInsuranceType(trimToEmpty(insuranceRecord.getInsuranceType()));
		insuranceRecord.setPolicyNo(trimToEmpty(insuranceRecord.getPolicyNo()));
		insuranceRecord.setInvoiceNo(trimToNull(insuranceRecord.getInvoiceNo()));
		insuranceRecord.setOcrTemplate(trimToNull(insuranceRecord.getOcrTemplate()));
		insuranceRecord.setPolicyFile(trimToNull(insuranceRecord.getPolicyFile()));
		insuranceRecord.setRemark(trimToNull(insuranceRecord.getRemark()));
	}

	private void validate(InsuranceRecord insuranceRecord) {
		if (Func.isEmpty(insuranceRecord.getVehicleType())) {
			throw new ServiceException("车船类型不能为空");
		}
		if (!"车辆".equals(insuranceRecord.getVehicleType()) && !"船舶".equals(insuranceRecord.getVehicleType())) {
			throw new ServiceException("车船类型不正确");
		}
		if (Func.isEmpty(insuranceRecord.getVehicleNo())) {
			throw new ServiceException("车牌号/船号不能为空");
		}
		if (Func.isEmpty(insuranceRecord.getInsuranceType())) {
			throw new ServiceException("保险类型不能为空");
		}
		if (Func.isEmpty(insuranceRecord.getPolicyNo())) {
			throw new ServiceException("保单号不能为空");
		}
		if (Func.isEmpty(insuranceRecord.getStartDate())) {
			throw new ServiceException("开始日期不能为空");
		}
		if (Func.isEmpty(insuranceRecord.getEndDate())) {
			throw new ServiceException("结束日期不能为空");
		}
		if (insuranceRecord.getEndDate().isBefore(insuranceRecord.getStartDate())) {
			throw new ServiceException("结束日期不能早于开始日期");
		}
		if (Func.isEmpty(insuranceRecord.getPremium())) {
			throw new ServiceException("保费不能为空");
		}
		validateNonNegative(insuranceRecord.getInsuredAmount(), "保额不能小于0");
		validateNonNegative(insuranceRecord.getPremium(), "保费不能小于0");
		validateLength(insuranceRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过50字");
		validateLength(insuranceRecord.getInsuranceType(), INSURANCE_TYPE_MAX_LENGTH, "保险类型不能超过50字");
		validateLength(insuranceRecord.getPolicyNo(), POLICY_NO_MAX_LENGTH, "保单号不能超过80字");
		validateLength(insuranceRecord.getInvoiceNo(), INVOICE_NO_MAX_LENGTH, "发票号不能超过80字");
		validateLength(insuranceRecord.getOcrTemplate(), OCR_TEMPLATE_MAX_LENGTH, "OCR识别模板不能超过100字");
		validateLength(insuranceRecord.getPolicyFile(), POLICY_FILE_MAX_LENGTH, "保单附件不能超过1000字");
		validateLength(insuranceRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字");
	}

	private void checkUniquePolicyNo(InsuranceRecord insuranceRecord) {
		Long count = count(Wrappers.<InsuranceRecord>lambdaQuery()
			.eq(InsuranceRecord::getIsDeleted, 0)
			.eq(InsuranceRecord::getVehicleType, insuranceRecord.getVehicleType())
			.eq(InsuranceRecord::getInsuranceType, insuranceRecord.getInsuranceType())
			.eq(InsuranceRecord::getPolicyNo, insuranceRecord.getPolicyNo())
			.ne(Func.isNotEmpty(insuranceRecord.getId()), InsuranceRecord::getId, insuranceRecord.getId()));
		if (count > 0) {
			throw new ServiceException("同一车船类型和保险类型下保单号已存在");
		}
	}

	private void validatePolicyFile(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			throw new ServiceException("请上传保单图片或PDF文件");
		}
		String filename = file.getOriginalFilename();
		if (Func.isEmpty(filename) || !filename.contains(".")) {
			throw new ServiceException("文件格式不正确");
		}
		String extension = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
		if (!SUPPORT_FILE_TYPES.contains(extension)) {
			throw new ServiceException("仅支持JPG、PNG、PDF文件");
		}
	}

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

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

	private BigDecimal nonNegative(BigDecimal value) {
		if (Func.isEmpty(value) || value.compareTo(BigDecimal.ZERO) >= 0) {
			return value;
		}
		return BigDecimal.ZERO;
	}

	private String normalizeVehicleType(String vehicleType) {
		String value = trimToEmpty(vehicleType);
		return value.isEmpty() ? "车辆" : 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;
	}

}
