package com.dcsoft.file.controller;

import cn.hutool.http.HttpUtil;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dcsoft.common.core.domain.R;
import com.dcsoft.common.core.exception.ServiceException;
import com.dcsoft.common.core.utils.StringUtils;
import com.dcsoft.common.core.utils.file.FileUtils;
import com.dcsoft.common.redis.service.RedisService;
import com.dcsoft.file.service.IFaceService;
import com.dcsoft.file.service.ISysFileService;
import com.dcsoft.file.utils.*;
import com.dcsoft.system.api.domain.SysFile;
import io.minio.MinioClient;
import io.minio.RemoveObjectArgs;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 文件请求处理
 *
 * @author dcsoft
 */
@RestController
public class SysFileController {
    private static final Logger log = LoggerFactory.getLogger(SysFileController.class);

    /**
     * 获取yml配置类里的桶名称
     */
    @Value("${minio.bucket-name}")
    private String bucketName;

    @Autowired
    private ISysFileService sysFileService;

    @Value("${minio.bucket-name1}")
    private String bucketName1;

    @Value("${minio.bucket-name3}")
    private String bucketName3;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IFaceService faceService;

    @Value("${minio.accessKey}")
    private String accessKey;

    @Value("${minio.secretKey}")
    private String secretKey;

    @Value("${minio.url}")
    private String miniourl;

    @Value("${sdk.upload}")
    public String upload;

    @Value("${minio.gwurl}")
    private String miniogwurl;

    @Value("${minio.bucket-name2}")
    private String bucketName2;

    @Value("${file.domain}")
    private String fileurl;

    @Value("${file.gwurl}")
    private String filegwurl;

    @Value("${yf.url:http://wo-api.uni-ubi.com}")
    private String yfUrl;

    @Value("${yf.projectGuid:3C1BA78F6FAD489AA0E6C7D285D8CFDC}")
    private String yfProjectGuid;

    @Value("${yf.appKey:7E28496B107D45D3B683B143E944D64B}")
    private String yfAppKey;

    @Value("${yf.appSecret:9D397690DAD64CFE9278FED5C3BCA68F}")
    private String yfAppSecret;

    private final String yfFaceDetectUrl = "/v2/algor/face/detect";


    /**
     * 文件上传请求
     */
    @PostMapping("upload")
    public R<SysFile> upload(MultipartFile file) {
        try {
            // 上传并返回访问地址
            String url = sysFileService.uploadFile(file);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(url));
            url = url.replace(fileurl, filegwurl);
            sysFile.setUrl(url);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 文件上传请求
     */
    @PostMapping("avatar")
    public R<SysFile> avatar(@RequestParam("avatarfile") MultipartFile file) {
        try {
            // 上传并返回访问地址
            String url = sysFileService.uploadFile(file);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(url));
            sysFile.setUrl(url);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    @PostMapping("uploadMinioCar")
    public R<SysFile> uploadMinioCar(@RequestParam("file") MultipartFile file) {
        try {
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName2, file.getName());
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    @PostMapping("uploadMinioCarBase64")
    public R<SysFile> uploadMinioCarBase64(@RequestBody JSONObject data) {
        try {
            String url = data.getString("url");
            if(StringUtils.isEmpty(url)){
                return R.fail("图片地址不能为空");
            }
            MultipartFile file = Base64ToMultipartFileUtil.convertToMultipartFile(url);

            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName2, file.getName());
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }


    /**
     * 文件上传请求
     */
    @PostMapping("uploadMinioPDF")
    public R<SysFile> uploadMinioPDF(MultipartFile file, String fileName) {

        try {
            // 上传并返回访问地址
            String fileNames = FileUploadUtils.uploadMinio(file, bucketName3, fileName);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }


    /**
     * 文件上传请求
     */
    @PostMapping("uploadMinio")
    public R<SysFile> uploadMinio(MultipartFile file, String fileName) {
       /* //判断压缩图片
        if((1024 * 1024 * 0.1) <= file.getSize()){
            // 小于 1M 的
            try {
                String fileNames1 = file.getOriginalFilename();
                File newFile = new File(fileNames1);
                if ((1024 * 1024 * 0.1) <= file.getSize() && file.getSize() <= (1024 * 1024)) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.4f).toFile(newFile);
                }
                // 1 - 2M 的
                else if ((1024 * 1024) < file.getSize() && file.getSize() <= (1024 * 1024 * 2)) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.2f).toFile(newFile);
                }
                // 2M 以上的
                else if ((1024 * 1024 * 2) < file.getSize()) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.1f).toFile(newFile);
                }
                // 转为 MultipartFile
                file = PictureUtils.getMultipartFile(newFile);
                newFile.delete();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }*/
        try {
            /*initFlowRules();//
            // 上传并返回访问地址
            //上传前进行人脸检测
            String base64String=MinioUtil.getBase64String(file);
            int data=faceService.judgeImageBase64(base64String);
            log.info("人脸检测返回值==========="+data);
            if(data!=0){
                log.error("人脸检测不符合要求");
                return R.fail("人脸检测不符合要求");
            }
            //提取特征值
            String feature=faceService.getFeature(base64String);*/
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName, fileName);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);

            sysFile.setUrl(fileNames);
            //sysFile.setFeature(feature);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 文件上传请求
     */
    @PostMapping("uploadMinios")
    public R<SysFile> uploadMinios(MultipartFile file, String fileName) {

        //判断压缩图片
        if ((1024 * 1024 * 0.1) <= file.getSize()) {
            // 小于 1M 的
            try {
                String fileNames1 = file.getOriginalFilename();
                File newFile = new File(fileNames1);
                if ((1024 * 1024 * 0.1) <= file.getSize() && file.getSize() <= (1024 * 1024)) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.4f).toFile(newFile);
                }
                // 1 - 2M 的
                else if ((1024 * 1024) < file.getSize() && file.getSize() <= (1024 * 1024 * 2)) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.2f).toFile(newFile);
                }
                // 2M 以上的
                else if ((1024 * 1024 * 2) < file.getSize()) {
                    Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.1f).toFile(newFile);
                }
                // 获取输入流
                FileInputStream input = new FileInputStream(newFile);
                // 转为 MultipartFile
                file = PictureUtils.getMultipartFile(newFile);
                newFile.delete();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            // 上传并返回访问地址
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName, fileName);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 文件非证件照上传请求
     */
    @PostMapping("uploadMinio1")
    public R<SysFile> uploadMinio1(MultipartFile file, String fileName) {
        try {
            try {
                // 裁剪图片为640*480
                String originalFilename = file.getOriginalFilename();
                File newFile = new File(originalFilename);
                Thumbnails.of(file.getInputStream()).crop(Positions.CENTER).size(480, 640).toFile(newFile);

                file = PictureUtils.getMultipartFile(newFile);
                newFile.delete();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            initFlowRules();
            //上传前进行人脸检测
            String imgBase64 = MinioUtil.getBase64String(file);
            checkPhoto(imgBase64);

            // 上传并返回访问地址
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName1, fileName);
//            checkPhoto(fileNames);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 文件非证件照上传请求
     */
    @PostMapping("uploadMinio3")
    public R<SysFile> uploadMinio3(MultipartFile file, String fileName) {
        try {
            // 上传并返回访问地址
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName1, fileName);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(fileNames));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 校验人脸质量是否合格
     *
     * @param imgBase64
     */
    private void checkPhoto(String imgBase64) {
        String token = redisService.getCacheObject("yf-Token");
        log.info("redis-token:{}", token);
        if (StringUtils.isBlank(token)) {
            try {
                long l = System.currentTimeMillis();
                String sign = DigestUtils.md5Hex(yfAppKey + l + yfAppSecret);
                Map<String, Object> map = new HashMap<>();
                map.put("projectGuid", yfProjectGuid);

                String result = HttpUtil.createGet(yfUrl + "/v1/" + yfProjectGuid + "/auth")
                        .header("appKey", yfAppKey)
                        .header("timestamp", String.valueOf(l))
                        .header("sign", sign)
                        .form(map)
                        .timeout(5000).execute().body();
                log.info("请求宇泛token-result:{}", result);
                JSONObject jsonObject1 = JSONObject.parseObject(result);
                if (jsonObject1.getInteger("result") == 1 && StringUtils.isNotBlank(jsonObject1.getString("data"))) {
                    token = jsonObject1.getString("data");
                    redisService.setCacheObject("yf-Token", token, 20 * 60 * 60L, TimeUnit.SECONDS);
                } else {
                    throw new ServiceException("宇泛鉴权失败！");
                }
            } catch (Exception e) {
                throw new ServiceException("宇泛鉴权失败！");
            }
        }

        //https://api.uni-ubi.com/wo/apis/V2.1/ai/portrait.html#%E4%BA%BA%E5%83%8F%E6%A3%80%E6%B5%8B
        Map<String, Object> map = new HashMap<>();
        map.put("imageUrl", "");
        map.put("imageBase64", imgBase64);
        map.put("returnLandmark", "true");
        map.put("returnAttributes", "true");
        map.put("unitTag", "");
        //0：检测全部属性是否合格
        map.put("validLevel", "0");

        //人脸算法校验
        String result = HttpUtil.createPost(yfUrl + yfFaceDetectUrl)
                .header("token", token)
                .header("projectGuid", yfProjectGuid)
                .body(JSON.toJSONString(map))
                .timeout(5000).execute().body();
        log.info("请求宇泛人脸返回：{}", result);
        JSONObject jsonObject1 = JSONObject.parseObject(result);
        if (jsonObject1.getInteger("result") != 1 || !jsonObject1.getBoolean("success")) {
            //token失效
            if (StringUtils.equals("WO_EXP-1203", jsonObject1.getString("code"))) {
                redisService.deleteObject("yf-Token");
                this.checkPhoto(imgBase64);
            } else {
                throw new ServiceException("人脸检测失败，请重新上传");
            }
        }

    }


    @PostMapping("uploadMinio2")
    public R<SysFile> uploadMinio2(MultipartFile file, String fileName, String name) {
        try {
            // 上传并返回访问地址
            String fileNames = FileUploadUtils.uploadMinio(file, this.bucketName1, fileName);
            SysFile sysFile = new SysFile();
            sysFile.setName(URLEncoder.encode(name, "UTF-8"));
            fileNames = fileNames.replace(miniourl, miniogwurl);
            sysFile.setUrl(fileNames);
            return R.ok(sysFile);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }


    /**
     * 文件上传请求
     */
    @GetMapping("compareTwoPic")
    public R<Float> compareTwoPic(@RequestParam("url1") String url1, @RequestParam("url2") String url2) {
        try {
            //进行人脸1v1
            byte[] image1 = Base64.decodeBase64(ImageToBase64Utils.getImgUrlToBase64(url1));
            byte[] image2 = Base64.decodeBase64(ImageToBase64Utils.getImgUrlToBase64(url2));
            float data = faceService.compareTwoPic(image1, image2);
            return R.ok(data);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 文件上传请求
     */
    @GetMapping("comparePic")
    public R<Float> comparePic(@RequestParam("feature1") String feature1, @RequestParam("feature2") String feature2) {
        try {
            //进行人脸1v1
            float data = faceService.compareTwoPic(feature1, feature2);
            return R.ok(data);
        } catch (Exception e) {
            log.error("上传文件失败", e);
            return R.fail(e.getMessage());
        }
    }

    private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        //通过QPS来限流
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //设置QPS为20.
        rule.setCount(10);
        rule.setLimitApp("default");
        rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }


    @PostMapping("/deleteFile")
    public R<String> deleteFile(String fileName) {
        try {
            // 创建MinIO客户端
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(miniourl)
                    .credentials(accessKey, secretKey)
                    .build();

            // 删除文件
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName1) // 替换为你实际的存储桶名称
                    .object(fileName)
                    .build());

            return R.ok("文件删除成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("文件删除失败：" + e.getMessage());
        }
    }

}
