package com.pj.project4sp.face.handler.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.pj.current.config.SystemObject;
import com.pj.project4sp.face.brand.FaceBrand;
import com.pj.project4sp.face.factory.FaceEngineFactory;
import com.pj.project4sp.face.handler.IFaceHandler;
import com.pj.project4sp.face.handler.VerifyVO;
import com.pj.utils.sg.AjaxError;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;

/**
 * 基于ArcSoft Face的人��识别
 */
@Service
@Slf4j
@DependsOn({"systemObject"})
public class ArcsoftFaceHandlerImpl implements IFaceHandler {

    //通用人脸识别引擎池
    private GenericObjectPool<FaceEngine> faceEngineGeneralPool;



    private ExecutorService compareExecutorService;

    @Override
    public boolean checkIsLive(String baseImg) {
        List<LivenessInfo> livenessInfoList = new ArrayList<>();
        FaceEngine faceEngine = null;
        try {
            faceEngine = faceEngineGeneralPool.borrowObject();
            faceEngine.getLiveness(livenessInfoList);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AjaxError("获取识别引擎失败");
        } finally {
            if (faceEngine != null) {
                faceEngineGeneralPool.returnObject(faceEngine);
            }
        }
        return livenessInfoList.get(0).getLiveness() == 1;
    }

    @Override
    public void createPersonByBase(String faceId, String name, String imageBase) {
        byte[] imageBytes = Base64.getDecoder().decode(imageBase);
        this.createPersonByBase(faceId, name, imageBytes);

    }

    @Override
    public void createPersonByBase(String faceId, String name, byte[] imageBytes) {
        String facePath = SystemObject.getFaceImgPath();
        File outputFile = new File(facePath + File.separator + faceId + ".png");
        FileUtil.del(outputFile);
        // 创建输出流
        try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
            // 写入数据到文件
            fileOutputStream.write(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deletePerson(String faceId) {
        String facePath = SystemObject.getFaceImgPath();
        File outputFile = new File(facePath + File.separator + faceId + ".png");
        FileUtil.del(outputFile);
    }

    @Override
    public boolean checkHasPerson(String img) {
        byte[] imageBytes = Base64.getDecoder().decode(img);
        return this.checkHasPerson(imageBytes);
    }

    @Override
    public boolean checkHasPerson(byte[] imageBase) {
        ImageInfo imageInfo = getRGBData(imageBase);
        List<FaceInfo> faceInfoList = new ArrayList<>();
        FaceEngine faceEngine = null;
        try {
            faceEngine = faceEngineGeneralPool.borrowObject();
            faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AjaxError("获取识别引擎失败");
        } finally {
            if (faceEngine != null) {
                faceEngineGeneralPool.returnObject(faceEngine);
            }
        }
        return faceInfoList.size() == 1;
    }

    @Override
    public VerifyVO verify(String faceId, String baseImage) {



        byte[] imageBytes = Base64.getDecoder().decode(baseImage);
       return this.verify(faceId,imageBytes);

    }

    @Override
    public VerifyVO verify(String faceId, byte[] imageBytes) {
        VerifyVO vo = new VerifyVO();
        String facePath = SystemObject.getFaceImgPath();
        File file = new File(facePath + File.separator + faceId + ".png");
        if (!file.exists()) {
            vo.setMsg("人员ID不存在");
            return vo;
        }
        ImageInfo sourceImageInfo = getRGBData(imageBytes);
        List<FaceInfo> sourceFaceInfoList = new ArrayList<>();
        FaceEngine faceEngine = null;
        try {
            faceEngine = faceEngineGeneralPool.borrowObject();
            faceEngine.detectFaces(sourceImageInfo.getImageData(), sourceImageInfo.getWidth(), sourceImageInfo.getHeight(), sourceImageInfo.getImageFormat(), sourceFaceInfoList);
            if (sourceFaceInfoList.size() == 0) {
                vo.setMsg("No faces");
                return vo;
            }
            if (sourceFaceInfoList.size() > 1) {
                vo.setMsg("图片中存在多个人脸");
                return vo;
            }
            FaceInfo faceInfo = sourceFaceInfoList.get(0);
            FaceFeature sourceFaceFeature = new FaceFeature();
            faceEngine.extractFaceFeature(sourceImageInfo.getImageData(), sourceImageInfo.getWidth(), sourceImageInfo.getHeight(), sourceImageInfo.getImageFormat(), faceInfo, sourceFaceFeature);

            //目标图片人脸
            List<FaceInfo> targeFaceInfoList = new ArrayList<>();
            ImageInfo imageInfo2 = getRGBData(file);
            faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), targeFaceInfoList);
            //特征提取
            FaceFeature targeFaceFeature = new FaceFeature();
            faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), targeFaceInfoList.get(0), targeFaceFeature);


            FaceSimilar faceSimilar = new FaceSimilar();
            faceEngine.compareFaceFeature(new FaceFeature(targeFaceFeature.getFeatureData()), new FaceFeature(sourceFaceFeature.getFeatureData()), faceSimilar);
            boolean result = faceSimilar.getScore() > 0.85f;
            String msg = result ? "人脸一致" : "不匹配";
            vo.setSuccess(result);
            vo.setMsg(msg);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AjaxError("获取识别引擎失败");
        } finally {
            if (faceEngine != null) {
                faceEngineGeneralPool.returnObject(faceEngine);
            }
        }
        return vo;
    }

    @Override
    public List<String> faceSearch(String baseImg) {
        return null;
    }

    @Override
    public FaceBrand faceBrand() {
        return FaceBrand.ARCSOFT;
    }


    @PostConstruct
    public void init() {

        if (!StrUtil.equals(SystemObject.config.getFaceType(), FaceBrand.ARCSOFT.getType())) {
            return;
        }
        String appId = SystemObject.config.getArcsoftAppid();
        String sdkKey = SystemObject.config.getArcsoftSdkKey();
        log.info("Initializing------:{}:{}", appId, sdkKey);

        GenericObjectPoolConfig detectPoolConfig = new GenericObjectPoolConfig();
        detectPoolConfig.setMaxIdle(5);
        detectPoolConfig.setMaxTotal(5);
        detectPoolConfig.setMinIdle(5);
        detectPoolConfig.setLifo(false);
        EngineConfiguration detectCfg = new EngineConfiguration();
        FunctionConfiguration detectFunctionCfg = new FunctionConfiguration();
        detectFunctionCfg.setSupportFaceDetect(true);//开启人脸检测功能
        detectFunctionCfg.setSupportFaceRecognition(true);//开启人脸识别功能
        detectCfg.setFunctionConfiguration(detectFunctionCfg);
        detectCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);//图片检测模式，如果是连续帧的视频流图片，那么改成VIDEO模式
        detectCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);//人脸旋转角度
        faceEngineGeneralPool = new GenericObjectPool(new FaceEngineFactory(appId, sdkKey, null, detectCfg), detectPoolConfig);//底层库算法对象池
        compareExecutorService = Executors.newFixedThreadPool(5);


    }


}
