package com.sonic.shark.utils;

import com.alibaba.fastjson.JSONObject;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.services.rekognition.AmazonRekognition;
import com.amazonaws.services.rekognition.AmazonRekognitionClientBuilder;
import com.amazonaws.services.rekognition.model.*;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.sonic.shark.domain.bo.FaceFeaturesBo;
import com.sonic.shark.enums.S3BucketNameEnum;
import com.sonic.shark.enums.ToastResultCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 亚马逊 图片 识别工具类
 * @Author code
 */
@Slf4j
@Component
public class AwsRecognitionUtils {

    @Value("${aws.s3.recognition.accessKeyId}")
    private String accessKey;
    @Value("${aws.s3.recognition.secretAccessKey}")
    private String secretAccessKey;

    private Map<S3BucketNameEnum, AmazonRekognition> clientMap = new ConcurrentHashMap<>();

    private AWSCredentials credentials;

    @PostConstruct
    public void init() {
        credentials = new YmlCredentials(accessKey, secretAccessKey);
    }

    /**
     * 获取client对象
     * @param s3BucketNameEnum
     * @return
     */
    public AmazonRekognition getClient(S3BucketNameEnum s3BucketNameEnum) {
        AmazonRekognition client = clientMap.get(s3BucketNameEnum);
        if(client == null) {
            client = AmazonRekognitionClientBuilder.standard()
                    .withRegion(s3BucketNameEnum.getRegions())
                    .withCredentials(new AWSStaticCredentialsProvider(credentials))
                    .build();
            clientMap.put(s3BucketNameEnum, client);
        }
        return client;
    }

    /**
     * S3 黄色暴力 鉴定
     * https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html
     * @param s3BucketNameEnum
     * @param fileFullPath
     * @return
     */
    public DetectModerationLabelsResult nsfwRecognition(S3BucketNameEnum s3BucketNameEnum, String fileFullPath) {
        try {
            Long startTime = System.currentTimeMillis();
            DetectModerationLabelsRequest request = new DetectModerationLabelsRequest()
                    .withImage(new Image().withS3Object(new S3Object().withName(fileFullPath).withBucket(s3BucketNameEnum.getBucketName())))
                    .withMinConfidence(60F);
                    //先不主动指定使用模型的版本号，让aws来主动决定进行自动切换
//                    .withRequestedModelVersion(ModerationRequestedModelVersion.V7_0);
            log.info("===> nsfwRecognition request : {}", request.toString());
            DetectModerationLabelsResult result = getClient(s3BucketNameEnum).detectModerationLabels(request);
            log.info("===> nsfwRecognition time : {} ms, modelVersion : {}, labels : {}", System.currentTimeMillis() - startTime, result.getModerationModelVersion(), result.getModerationLabels());
            return result;
        } catch (InvalidImageFormatException e) {
            log.error("===> AwsRecognitionUtils nsfwRecognition error: ", e);
            boolean isGif = fileFullPath.endsWith(".gif");
            //图片格式无效的异常提示
            ToastResultCode.SYSTEM_EXCEPTION.check(!isGif, "Invalid image format");
            return null;
        } catch (Exception e) {
            log.error("===> AwsRecognitionUtils nsfwRecognition error: ", e);
            ToastResultCode.SYSTEM_EXCEPTION.check(true);
            return null;
        }
    }


    /**
     * 图片标签识别
     * @param s3BucketEnum
     * @param fileFullPath
     * @return
     */
    public String imageTagRecognition(S3BucketNameEnum s3BucketEnum, String fileFullPath) {
        try {
            DetectLabelsRequest request = new DetectLabelsRequest()
                    .withImage(new Image().withS3Object(new S3Object().withName(fileFullPath).withBucket(s3BucketEnum.getBucketName())))
                    .withMaxLabels(150).withMinConfidence(30F);
            DetectLabelsResult result = getClient(s3BucketEnum).detectLabels(request);
            List<Label> labels = result.getLabels();
            String resultLabels = JSONObject.toJSONString(labels);
            return resultLabels;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("===> AwsRecognitionUtils imageTagRecognition error: ", e);
        }
        return null;
    }

    /**
     * 通过面部识别获取最小年龄
     * @param s3BucketEnum
     * @param fileFullPath
     * @return
     */
    public Integer getMinAgeByFaceRecognition(S3BucketNameEnum s3BucketEnum, String fileFullPath){
        List<FaceDetail> faceDetails = faceRecognition(s3BucketEnum, fileFullPath);
        log.info("getMinAgeByFaceRecognition:{}", JSONObject.toJSONString(faceDetails));
        if(CollectionUtils.isNotEmpty(faceDetails)){
            for (FaceDetail face: faceDetails) {
                //获取年龄的属性
                AgeRange ageRange = face.getAgeRange();
                if(ageRange != null && ageRange.getLow() != null && ageRange.getHigh() != null){
                    //取值年龄范围的平均值进行计算
                    return (ageRange.getHigh() + ageRange.getLow()) / 2;
                }
            }
        }
        return null;
    }

    /**
     * 通过面部识别获取用户人脸特征(最小年龄、性别)
     * @param s3BucketEnum
     * @param fileFullPath
     * @return
     */
    public FaceFeaturesBo getFaceFeaturesByFaceRecognition(S3BucketNameEnum s3BucketEnum, String fileFullPath){
        FaceFeaturesBo faceFeaturesBo = new FaceFeaturesBo();
        List<FaceDetail> faceDetails = faceRecognition(s3BucketEnum, fileFullPath);
        log.info("getMinAgeByFaceRecognition:{}", JSONObject.toJSONString(faceDetails));
        if(CollectionUtils.isNotEmpty(faceDetails)){
            for (FaceDetail face: faceDetails) {
                //获取年龄的属性
                AgeRange ageRange = face.getAgeRange();
                if(ageRange != null && ageRange.getLow() != null && ageRange.getHigh() != null){
                    //取值年龄范围的平均值进行计算
                    faceFeaturesBo.setAge((ageRange.getHigh() + ageRange.getLow()) / 2);
                }
                //获取性别属性
                Gender gender = face.getGender();
                if(gender != null && StringUtils.isNotEmpty(gender.getValue())) {
                    //性别，分数
                    faceFeaturesBo.setSex("Male".equalsIgnoreCase(gender.getValue()) ? 0 : "Female".equalsIgnoreCase(gender.getValue()) ? 1 : 2);
                    faceFeaturesBo.setSexConfidence(Double.valueOf(gender.getConfidence()));
                }
            }
        }
        return faceFeaturesBo;
    }

    /**
     * 面部识别
     * @param s3BucketEnum
     * @param fileFullPath
     */
    public List<FaceDetail> faceRecognition(S3BucketNameEnum s3BucketEnum, String fileFullPath){
        try {
            DetectFacesRequest request = new DetectFacesRequest()
                    .withImage(new Image()
                            .withS3Object(new S3Object()
                                    .withName(fileFullPath)
                                    .withBucket(s3BucketEnum.getBucketName())))
                    .withAttributes(Attribute.ALL);
            DetectFacesResult detectFacesResult = getClient(s3BucketEnum).detectFaces(request);
            List<FaceDetail> faceDetails = detectFacesResult.getFaceDetails();
            return faceDetails;
        }catch (Exception e){
            e.printStackTrace();
            log.error("===> AwsRecognitionUtils faceRecognition error: ", e);
        }
        return null;
    }

}
