package com.sonic.shark.service.impl;

import com.amazonaws.services.rekognition.model.DetectModerationLabelsResult;
import com.amazonaws.services.rekognition.model.ModerationLabel;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sonic.shark.dao.NsfwConfigDao;
import com.sonic.shark.domain.bo.NsfwRecognitionResult;
import com.sonic.shark.domain.entity.NsfwConfig;
import com.sonic.shark.enums.S3BucketNameEnum;
import com.sonic.shark.service.NsfwConfigService;
import com.sonic.shark.utils.AwsRecognitionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class NsfwConfigServiceImpl extends ServiceImpl<NsfwConfigDao, NsfwConfig> implements NsfwConfigService {

    @Autowired
    private AwsRecognitionUtils awsRecognitionUtils;

    @Override
    public NsfwRecognitionResult nsfwRecognition(S3BucketNameEnum s3BucketNameEnum, String fileFullPath) {
        return nsfwRecognition(s3BucketNameEnum, fileFullPath, NsfwConfig.VersionType.DEFAULT.name());
    }


    @Override
    public NsfwRecognitionResult nsfwRecognition(S3BucketNameEnum s3BucketNameEnum, String fileFullPath, String versionType) {
        //构造返回结果
        NsfwRecognitionResult result = new NsfwRecognitionResult();
        //获取图片识别的标签
        DetectModerationLabelsResult moderationLabelsResult = awsRecognitionUtils.nsfwRecognition(s3BucketNameEnum, fileFullPath);
        //没有获取到标签，直接当审核通过处理
        if(moderationLabelsResult == null) {
            result.setBl(false);
            return result;
        }
        //获取标签列表
        List<ModerationLabel> labelList = moderationLabelsResult.getModerationLabels();
        //获取使用的模型版本号
        String modelVersion = moderationLabelsResult.getModerationModelVersion();

        result.setLabelList(labelList);
        //根据版本号来判断看到底走那个逻辑(6.1版本走老逻辑，其他版本都走新逻辑)
        //将标签评分和数据库配置的最小评分进行比较 得出鉴黄结果
        result.setBl(checkNsfw(labelList, versionType));
        return result;
    }

    @Override
    public Boolean checkNsfw(List<ModerationLabel> labelList, String versionType) {
        List<String> categoryList = labelList.stream().map(e -> e.getName()).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(categoryList)) {
            return false;
        }
        Map<String, Float> categoryMap = getScore(categoryList, versionType);
        if(categoryMap == null || categoryMap.isEmpty()) {
            return false;
        }
        log.info("===> checkNsfw labelList all : {}", labelList);
        //有三级分类，根据三级分类将所有的这个类型标签的数据过滤出来进行判断
        List<ModerationLabel> level3LabelList = labelList.stream().filter(e -> e.getTaxonomyLevel() == 3).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(level3LabelList)) {
            //先做分数验证
            Boolean bl = checkScore(categoryMap, level3LabelList);
            if(bl) {
                return true;
            }
            //先过滤掉3级分类的数据
            labelList = labelList.stream().filter(e -> e.getTaxonomyLevel() != 3).collect(Collectors.toList());
            //根据3级分类找到2级分类 并过滤掉
            List<String> level2LabelNameList = level3LabelList.stream().map(e -> e.getParentName()).collect(Collectors.toList());
            List<ModerationLabel> level2LabelList = labelList.stream().filter(e -> level2LabelNameList.contains(e.getName())).collect(Collectors.toList());
            //过滤掉2级分类的数据
            labelList = labelList.stream().filter(e -> !level2LabelNameList.contains(e.getName())).collect(Collectors.toList());
            //根据2级分类找到1级分类 并过滤掉
            List<String> level1LabelNameList = level2LabelList.stream().map(e -> e.getParentName()).collect(Collectors.toList());
            //过滤掉1级分类的数据
            labelList = labelList.stream().filter(e -> !level1LabelNameList.contains(e.getName())).collect(Collectors.toList());
        }
        log.info("===> checkNsfw labelList level3 : {}", labelList);
        //还有二级分类，根据二级分类将所有的这个类型标签的数据过滤出来进行判断
        List<ModerationLabel> level2LabelList = labelList.stream().filter(e -> e.getTaxonomyLevel() == 2).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(level2LabelList)) {
            //先做分数验证
            Boolean bl = checkScore(categoryMap, level2LabelList);
            if(bl) {
                return true;
            }
            //先过滤掉2级分类的数据
            labelList = labelList.stream().filter(e -> e.getTaxonomyLevel() != 2).collect(Collectors.toList());
            //根据2级分类找到1级分类 并过滤掉
            List<String> level1LabelNameList = level2LabelList.stream().map(e -> e.getParentName()).collect(Collectors.toList());
            //过滤掉1级分类的数据
            labelList = labelList.stream().filter(e -> !level1LabelNameList.contains(e.getName())).collect(Collectors.toList());
        }
        log.info("===> checkNsfw labelList level2 : {}", labelList);
        //还有一级分类，直接过滤出来进行判断
        List<ModerationLabel> level1LabelList = labelList.stream().filter(e -> e.getTaxonomyLevel() == 1).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(level1LabelList)) {
            //先做分数验证
            Boolean bl = checkScore(categoryMap, level1LabelList);
            if(bl) {
                return true;
            }
        }
        log.info("===> checkNsfw labelList level1 : {}", labelList);
        return false;
    }

    /**
     * 标签得分校验操作
     * @param categoryMap
     * @param list
     * @return  true 代表为黄图
     */
    private Boolean checkScore(Map<String, Float> categoryMap, List<ModerationLabel> list) {
        for (ModerationLabel label : list) {
            Float score = categoryMap.get(label.getName());
            //字段解释：confidence 表示置信度，数值越高表示图片和标签说明越接近
            //aws没有返回标签分值 或者 数据库没有配置分值 则直接跳过当前标签的校验
            if(score == null || label.getConfidence() == null) {
                continue;
            }
            //aws的值 大于 配置值 则 为黄图
            //数据库配置的分值越小越严格  数据库配置的分值越大越放宽
            if(label.getConfidence().compareTo(score) > 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Map<String, Float> getScore(List<String> categoryList, String versionType) {
        List<NsfwConfig> list = list(Wrappers.<NsfwConfig>lambdaQuery()
                .select(NsfwConfig::getCategory, NsfwConfig::getParentCategory, NsfwConfig::getScore)
                .in(NsfwConfig::getCategory, categoryList)
                .eq(StringUtils.isNotEmpty(versionType), NsfwConfig::getVersionType, versionType));
        return list.stream().collect(Collectors.toMap(NsfwConfig::getCategory, NsfwConfig::getScore));
    }

}
