package com.ktg.common.utils;


import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.ktg.common.vo.VerificationVO;
import com.machinezoo.sourceafis.FingerprintImage;
import com.machinezoo.sourceafis.FingerprintMatcher;
import com.machinezoo.sourceafis.FingerprintTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <p>
 * FingerprintComparison<br>
 * 指纹比对算法(dat)
 * </p>
 *
 * @author CGJ
 * @version 1.0
 * @since 2025年03月07日 11:51
 */
@Slf4j
public class FingerprintComparisonByDat {

    // 相似度门槛
    private static final double THRESHOLD = 40; // 相当于错误率是0.01%，THRESHOLD越高，错误率越低
    private static final ExecutorService THREAD_POOL_EXECUTOR = Executors.newFixedThreadPool(4); // 线程池

    public static VerificationVO completableFutureComparison(final MultipartFile file, final Set<String> matcherDat) throws IOException {
        // 转成list
        List<String> matcherImgList = new ArrayList<>(matcherDat);
        // 切分四等份
        int denominator = 1;
        if (matcherImgList.size() >= 4) {
            denominator = 4;
        }
        List<List<String>> averageMatcherImgList = Lists.partition(matcherImgList, matcherImgList.size() / denominator);
        // 开始解析输入的指纹到指纹模板
        byte[] bytes = file.getBytes();
        // 创建FingerprintImage对象
        FingerprintImage fingerprintImage = new FingerprintImage()
                .dpi(500) // 设置DPI，具体值取决于你的图像分辨率
                .decode(bytes);
        // 提取指纹特征值
        FingerprintTemplate fingerprintTemplate = new FingerprintTemplate(fingerprintImage);
        // 构建四个线程进行处理，防止人员过多对比速度太慢
        CompletableFuture<VerificationVO>[] completableFutureArray = averageMatcherImgList.stream().map(
                partitionFingerprint -> CompletableFuture.supplyAsync(
                        () -> comparison(fingerprintTemplate, new ArrayList<>(partitionFingerprint)), THREAD_POOL_EXECUTOR)
        ).toArray(CompletableFuture[]::new);
        // 等待所有任务执行完
        CompletableFuture.allOf(completableFutureArray).join();
        List<VerificationVO> verificationList = new ArrayList<>();
        for (CompletableFuture<VerificationVO> completableFuture : completableFutureArray) {
            try {
                VerificationVO verification = completableFuture.get();
                if (ObjectUtil.isNotEmpty(verification)) {
                    verificationList.add(verification);
                }
            } catch (InterruptedException | ExecutionException e) {
                log.error(e.getMessage(), e);
            }
        }
        // 找出最匹配的指纹（匹配度最高）
        if (ObjectUtil.isNotEmpty(verificationList)) {
            VerificationVO max = verificationList.stream().max(Comparator.comparing(VerificationVO::getScore)).get();
            log.info("相似值最佳的的指纹：{}，分数{}", max.getFingerprint(), max.getScore());
            return max;
        }
        return null;
    }

    public static VerificationVO comparison(final FingerprintTemplate fingerprintTemplate, final List<String> matcherDatList) {
        try {
            if (!matcherDatList.isEmpty()) {
                // 输入的被验证指纹
                FingerprintMatcher matcher = new FingerprintMatcher(fingerprintTemplate);
                // 最匹配的指纹
                String match = null;
                // 峰值
                double high = 0;
                for (String matcherDat : matcherDatList) {
                    // 输入的指纹和指纹库中的指纹进行对比，找到当前线程中的分数最高的指纹
                    boolean exists = new File(matcherDat).exists();
                    if (!exists) {
                        continue;
                    }
                    FingerprintTemplate matcherTemp = new FingerprintTemplate().deserialize(new String(Files.readAllBytes(Paths.get(matcherDat))));
                    double score = matcher.match(matcherTemp);
                    if (score > high) {
                        high = score;
                        match = matcherDat;
                    }
                }
                return high >= THRESHOLD ? new VerificationVO().setFingerprint(match).setScore(high) : null;
            }
        } catch (Exception e) {
            log.error("指纹比对异常：{}", e.getMessage());
        }
        return null;
    }

}


