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

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.pj.project4sp.face.brand.FaceBrand;
import com.pj.project4sp.face.handler.IFaceHandler;
import com.pj.project4sp.face.handler.VerifyVO;
import com.pj.project4sp.face.properties.TencenProperties;
import com.pj.utils.sg.AjaxError;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20200303.IaiClient;
import com.tencentcloudapi.iai.v20200303.models.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

/**
 * 人脸库管理地址
 * https://console.cloud.tencent.com/aiface/face-lib
 */
@Service
@Slf4j
public class TencenFaceHandlerImpl implements IFaceHandler {
    @Resource
    private TencenProperties tencenProperties;

    @Override
    public VerifyVO verify(String personId, String baseImage) {
        VerifyVO vo = new VerifyVO();
        vo.setSuccess(false);
        IaiClient client = this.createClient();
        VerifyPersonRequest req = new VerifyPersonRequest();
        req.setImage(baseImage);
        req.setPersonId(personId);
        // 返回的resp是一个VerifyPersonResponse的实例，与请求对象对应
        VerifyPersonResponse resp;
        try {
            resp = client.VerifyPerson(req);
        } catch (TencentCloudSDKException e) {
            log.error("verify person : {} fail,{}", personId, e.getMessage());
            StaticLog.info("verify person : {} fail,{}", personId, e.getMessage());
            vo.setMsg(e.getMessage());
            return vo;
        }
        boolean result = resp != null && resp.getIsMatch();
        vo.setMsg(result ? "成功" : "不匹配");
        vo.setSuccess(result);
        return vo;
    }

    @Override
    public VerifyVO verify(String faceId, byte[] imageBytes) {
        String base64Images = Base64.getEncoder().encodeToString(imageBytes);
        return verify(faceId, base64Images);
    }

    /**
     * 查找人脸库
     *
     * @param baseImg
     * @return
     */
    public List<String> faceSearch(String baseImg) {
        StaticLog.info("face:{}", baseImg);
        IaiClient client = this.createClient();
        SearchFacesRequest request = new SearchFacesRequest();
        request.setImage(baseImg);
        request.setMaxFaceNum(1L);
        request.setMinFaceSize(80L);
        request.setMaxPersonNum(2L);
        request.setGroupIds(new String[]{tencenProperties.getGroupId()});
        SearchFacesResponse response;
        List<String> faceId = new ArrayList<>();
        try {
            response = client.SearchFaces(request);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            StaticLog.error("face error: " + e.getMessage());
            throw new AjaxError("无人脸信息");
        }
        Arrays.stream(response.getResults())
                .forEach(result -> {
                    Arrays.stream(result.getCandidates())
                            .filter(candidate -> candidate.getScore() >= 80)
                            .forEach(candidate -> faceId.add(candidate.getPersonId()));
                });
        return faceId;
    }

    public void createPersonByBase(String personId, String name, String imageBase) {
        IaiClient client = this.createClient();
        // 实例化一个请求对象,每个接口都会对应一个request对象
        CreatePersonRequest req = new CreatePersonRequest();
        req.setGroupId(tencenProperties.getGroupId());
        req.setPersonName(name);
        req.setPersonId(personId);
        req.setImage(imageBase);
        // 返回的resp是一个CreatePersonResponse的实例，与请求对象对应
        try {
            CreatePersonResponse response = client.CreatePerson(req);
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void createPersonByBase(String faceId, String name, byte[] imageBase) {
        String base64Images = Base64.getEncoder().encodeToString(imageBase);
        createPersonByBase(faceId, name, base64Images);
    }

    @Override
    public void deletePerson(String faceId) {
        IaiClient client = this.createClient();
        DeletePersonRequest request = new DeletePersonRequest();
        request.setPersonId(faceId);
        try {
            DeletePersonResponse response = client.DeletePerson(request);
            String requestId = response.getRequestId();
            log.info("delete face : {},{}", faceId, requestId);
        } catch (TencentCloudSDKException e) {
            log.error("delete face fail,{}", e.getMessage());
        }
    }

    @Override
    public boolean checkHasPerson(String img) {
        IaiClient client = this.createClient();
        // 实例化一个请求对象,每个接口都会对应一个request对象
        DetectFaceRequest req = new DetectFaceRequest();
        req.setMaxFaceNum(1L);
        req.setNeedFaceAttributes(1L);
        req.setNeedQualityDetection(1L);
        req.setImage(img);
        // 返回的resp是一个DetectFaceResponse的实例，与请求对象对应
        DetectFaceResponse resp = null;
        try {
            resp = client.DetectFace(req);
        } catch (TencentCloudSDKException e) {
            log.error("Error while:{}", e.getMessage());
            return false;
        }
        if (resp == null || StrUtil.contains(AbstractModel.toJsonString(resp), "NoFaceInPhoto")) {
            return false;
        }
        // 输出json格式的字符串回包
        log.info(AbstractModel.toJsonString(resp));
        FaceInfo[] faceInfos = resp.getFaceInfos();
        if (faceInfos.length > 1) {
            throw new AjaxError("存在多个人脸");
        }
        FaceInfo faceInfo = faceInfos[0];
        Long score = faceInfo.getFaceQualityInfo().getScore();
        if (score == null || score < 80) {
            FaceQualityInfo faceQualityInfo = faceInfo.getFaceQualityInfo();
            Long brightness = faceQualityInfo.getBrightness();
            if (brightness == null || brightness < 30) {
                throw new AjaxError("光线不足");
            }
            if (brightness > 70) {
                throw new AjaxError("光线太亮");
            }
            FaceQualityCompleteness completeness = faceQualityInfo.getCompleteness();
            if (completeness.getMouth() == null || completeness.getMouth() < 50) {
                throw new AjaxError("请露出嘴巴");
            }
            if (completeness.getChin()==null||completeness.getChin()<70) {
                throw new AjaxError("请露出下巴");
            }
            FaceAttributesInfo faceAttributesInfo = faceInfo.getFaceAttributesInfo();
            if (!faceAttributesInfo.getEyeOpen()) {
                throw new AjaxError("请睁开眼");
            }

        }

        return true;
    }

    @Override
    public boolean checkHasPerson(byte[] imageBase) {
        String base64Images = Base64.getEncoder().encodeToString(imageBase);
        return checkHasPerson(base64Images);
    }

    public boolean checkIsLive(String baseImg) {
        IaiClient client = this.createClient();
        DetectLiveFaceRequest req = new DetectLiveFaceRequest();
        req.setImage(baseImg);
        DetectLiveFaceResponse resp;
        // 返回的resp是一个DetectLiveFaceResponse的实例，与请求对象对应
        try {
            resp = client.DetectLiveFace(req);
        } catch (TencentCloudSDKException e) {
            log.error("check live fail,{}", e.getMessage());
            throw new AjaxError(e.getMessage());
        }
        return resp != null && resp.getIsLiveness();
    }

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

    private IaiClient createClient() {
        // 实例化一个认证对象，入参需要传入腾讯云账户secretId，secretKey,此处还需注意密钥对的保密
        // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
        Credential cred = new Credential(tencenProperties.getSecretId(), tencenProperties.getSecretKey());
        // 实例化一个http选项，可选的，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("iai.tencentcloudapi.com");
        // 实例化一个client选项，可选的，没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        return new IaiClient(cred, "ap-chongqing", clientProfile);
    }

}
