package org.springblade.thirdparty.ocr.convert;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springblade.thirdparty.ocr.constant.OCRImageType;
import org.springblade.thirdparty.ocr.exception.OCRException;
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *  附件索引转换器
 * @author bfhuange
 * @date 2024/11/8
 */
@Slf4j
@AllArgsConstructor
@Getter
public enum AttachmentIndexConvert {
    /**
     *  车头
     */
    CAR_FRONT(List.of(OCRImageType.CAR_FRONT), TransportCertificateVO::getCarFrontIndexes, TransportCertificateVO::getOtherIndexes),
    /**
     *  车尾
     */
    CAR_BACK(List.of(OCRImageType.CAR_BACK), TransportCertificateVO::getCarBackIndexes, TransportCertificateVO::getOtherIndexes),
    /**
     *  行驶证 只从 VEHICLE_LICENSE_MAIN、VEHICLE_LICENSE_MAIN_OTHERS 取车牌号，VEHICLE_LICENSE_SIDE、VEHICLE_LICENSE_MAIN_GUA，没有车牌，但是要分类成行驶证
     */
    VEHICLE_LICENSE(List.of(OCRImageType.VEHICLE_LICENSE_MAIN, OCRImageType.VEHICLE_LICENSE_MAIN_OTHERS, OCRImageType.VEHICLE_LICENSE_SIDE, OCRImageType.VEHICLE_LICENSE_MAIN_GUA), TransportCertificateVO::getVehicleLicenseIndexes, TransportCertificateVO::getOtherIndexes, false),
    /**
     *  驾驶证 只从 DRIVER_LICENSE_MAIN、DRIVER_LICENSE_ELEC 取有效期，DRIVER_LICENSE_SIDE 没有有效期，但是要分类驾驶证
     */
    DRIVER_LICENSE(List.of(OCRImageType.DRIVER_LICENSE_MAIN, OCRImageType.DRIVER_LICENSE_ELEC, OCRImageType.DRIVER_LICENSE_SIDE), TransportCertificateVO::getDriverLicenseIndexes, TransportCertificateVO::getOtherIndexes, true),
    /**
     *  其他
     */
    OTHER(List.of(OCRImageType.ID_CARD_MAIN, OCRImageType.ID_CARD_SIDE, OCRImageType.UNKNOWN, OCRImageType.OTHERS, OCRImageType.CARD,
            OCRImageType.SCRAP, OCRImageType.NO_PLATE, OCRImageType.NO_CAR), TransportCertificateVO::getOtherIndexes, TransportCertificateVO::getOtherIndexes,  true),
    /**
     *  磅单
     */
    POUND(Collections.emptyList(), TransportCertificateVO::getPoundIndexes, TransportCertificateVO::getOtherIndexes),
    ;

    /**
     *  图像类型列表
     */
    private final List<OCRImageType> imageTypes;
    /**
     *  是否多个，除了其他，都是单个
     */
    private final boolean multi;
    /**
     *  默认附件索引列表
     */
    private final Function<TransportCertificateVO, List<Integer>> defaultListGetter;
    /**
     *  单个的情况下，其他的附件放的索引列表
     */
    private final Function<TransportCertificateVO, List<Integer>> otherListGetter;
    /**
     *  多个的情况下，是否设置多次，后面的会覆盖前面的
     */
    private final boolean multiSet;

    AttachmentIndexConvert(List<OCRImageType> imageTypes, Function<TransportCertificateVO, List<Integer>> defaultListGetter, Function<TransportCertificateVO, List<Integer>> otherListGetter) {
        this(imageTypes, false, defaultListGetter, otherListGetter, true);
    }

    AttachmentIndexConvert(List<OCRImageType> imageTypes, Function<TransportCertificateVO, List<Integer>> defaultListGetter, Function<TransportCertificateVO, List<Integer>> otherListGetter, boolean multiSet) {
        this(imageTypes, true, defaultListGetter, otherListGetter, multiSet);
    }

    /**
     *  添加索引到list
     * @param certificate 凭证
     * @param index 索引
     * @return
     */
    public boolean addIndex2list(TransportCertificateVO certificate, Integer index) {
        List<Integer> list = defaultListGetter.apply(certificate);
        // 是否放入默认list
        boolean defaultList = true;
        if (!multi && !list.isEmpty() && !list.contains(index)) {
            // 单个且默认list已经有数据了且待放入的数据不在默认list，放入其他
            // 处理同一张图包含能取字段的驾驶证或行驶证以及不能取字段的驾驶证或行驶证时，不能取字段的驾驶证或行驶证类型先识别，导致后续把能取字段的驾驶证或行驶证类型放到其他
            list = otherListGetter.apply(certificate);
            defaultList = false;
        }
        if (list.contains(index)) {
            // 如果已经包含了图片，设置多个，返回true，不设置多个，返回false
            return multiSet;
        }
        // 没有当前索引才添加，防止一张图片识别出多个结果重复添加索引
        list.add(index);
        return defaultList;
    }

    /**
     *  图像类型对应的附件转换
     */
    private static final Map<String, AttachmentIndexConvert> CONVERT_MAP = initConvertMap();

    /**
     *  初始化 图像类型对应的附件转换
     * @return
     */
    private static Map<String, AttachmentIndexConvert> initConvertMap() {
        return Stream.of(values())
                .flatMap(convert -> convert.imageTypes.stream()
                        .collect(Collectors.toMap(OCRImageType::getId, e -> convert))
                        .entrySet().stream()
                ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
                    throw new OCRException("图像类型对应的附件转换重复");
                }));
    }

    /**
     *  根据typeId 查询转换器，没找到的是磅单
     * @param typeId
     * @return
     */
    public static AttachmentIndexConvert getConvertByTypeId(String typeId) {
        // 磅单的typeId过多，还在新增，所以没有配置的都认为是磅单
        return CONVERT_MAP.getOrDefault(typeId, AttachmentIndexConvert.POUND);
    }

    public List<String> getImageTypeIds() {
        return imageTypes.stream()
                .map(OCRImageType::getId)
                .collect(Collectors.toList());
    }
}
