package com.persagy.dmp.file.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import com.persagy.dmp.common.constant.CommonConstant;
import com.persagy.dmp.common.constant.ResponseCode;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.common.model.response.CommonResult;
import com.persagy.dmp.file.client.FileClientFacade;
import com.persagy.dmp.file.client.FileMd5ClientFacade;
import com.persagy.dmp.file.constant.FileCommonConst;
import com.persagy.dmp.file.constant.UploadCodeEnum;
import com.persagy.dmp.file.model.*;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.List;

/**
 * 文件存储助手
 * @author Charlie Yu
 * @date 2021-05-15
 */
@Slf4j
public class FileStorageHelper {

    /**
     * 上传文件
     * @param fileInfo
     * @param in
     * @return
     */
    public static String uploadFile(FileInfo fileInfo, InputStream in) {
        // 1.获得文件大小
        byte[] streamBytes = getStreamBytes(in);
        // 2.获得文件的md5值
        fileInfo.setFileMd5(DigestUtil.md5Hex(streamBytes));
        FileRequestData requestData = new FileRequestData();
        requestData.setGroupCode(fileInfo.getGroupCode());
        requestData.setBusinessId(fileInfo.getBusinessId());
        requestData.setExpireDate(fileInfo.getExpireDate());
        requestData.setFileBucket(fileInfo.getFileBucket());
        requestData.setFileName(fileInfo.getFileName());
        requestData.setFileSize((long) streamBytes.length);
        requestData.setFileMd5(fileInfo.getFileMd5());
        requestData.setFileId(fileInfo.getId());
        CommonResult<UploadMes> mesCommonResult = FileClientFacade
                .initSingleUploadPrototype(fileInfo.getGroupCode(), null, null, null, requestData);
        if (!CommonConstant.QUERY_SUCCESS.equals(mesCommonResult.getResult())){
            throw new BusinessException(mesCommonResult.getResult(),mesCommonResult.getMessage());
        }
        UploadMes uploadMes = mesCommonResult.getData();
        List<UploadSubMes> content = uploadMes.getContent();
        if (UploadCodeEnum.CODE_200.getCode().equals(uploadMes.getUploadCode())){
            // 秒传
            return uploadMes.getId();
        }
        if (CollUtil.isEmpty(content) || StrUtil.isBlank(content.get(0).getUploadUrl())){
            throw new BusinessException(ResponseCode.B0300.getCode(),ResponseCode.B0300.getDesc());
        }
        HttpResponse response = HttpRequest
                .put(content.get(0).getUploadUrl())
                .body(streamBytes).execute();
        if (!response.isOk()){
            log.error("上传文件出错:{}",response.body());
            throw new BusinessException(ResponseCode.B0001.getCode(),ResponseCode.B0001.getDesc());
        }
        return uploadMes.getId();
    }

    /***
     * Description: 读取流的字节数组
     * @param stream : 流
     * @return : byte[]
     * @author : lijie
     * @date :2021/10/23 12:22
     * Update By lijie 2021/10/23 12:22
     */
    private static byte[] getStreamBytes(InputStream stream) {
        return IoUtil.readBytes(stream);
    }

    /**
     * 上传图片
     * @param fileInfo
     * @param in
     * @return
     */
    public static String uploadImage(FileInfo fileInfo, InputStream in) {
        // 图片压缩
        InputStream cutIn = ImageHelper.cutImage(in);
        return uploadFile(fileInfo, cutIn);
    }

    /**
     * 修改文件
     * @param fileId
     * @param fileName
     * @param in
     * @return
     */
    public static String replaceFile(String fileId, String fileName, InputStream in) {
        FileInfo fileInfo = FileClientFacade.load(fileId);
        byte[] streamBytes = getStreamBytes(in);
        // 1.判断文件是否已存在,如果已存在则更新文件信息关联的MD5值即可,秒传
        String fileMd5Str = DigestUtil.md5Hex(streamBytes);
        FileMd5 newFileMd5 = FileMd5ClientFacade.loadByMd5(fileMd5Str);
        if (null!=newFileMd5){
            fileInfo.setFileMd5(fileMd5Str);
            fileInfo.setFileName(fileName);
            FileClientFacade.update(fileInfo);
            return fileInfo.getId();
        }
        // 2.判断md5关联的文件信息是否只有当前一个,如果只有一个则删除历史文件
        List<FileInfo> fileInfos = FileClientFacade.queryByFileMd5(fileInfo.getFileMd5());
        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
        if (CollUtil.isNotEmpty(fileInfos) && fileInfos.size()==1){
            // 删除MD5文件信息
            FileMd5ClientFacade.delete(fileMd5.getId());
        }
        // 3.更新文件信息,然后重新上传文件
        fileInfo.setFileMd5(fileMd5Str);
        fileInfo.setFileName(fileName);
        uploadFile(fileInfo,IoUtil.toStream(streamBytes));
        return fileInfo.getId();
    }

    /**
     * 更新图片
     * @param fileId
     * @param fileName
     * @param in
     * @return
     */
    public static String replaceImage(String fileId, String fileName, InputStream in) {
        // 图片压缩
        InputStream cutIn = ImageHelper.cutImage(in);
        return replaceFile(fileId, fileName, cutIn);
    }

    /**
     * 删除文件及图片
     * @param fileId
     */
    public static void deleteFile(String fileId) {
        FileInfo fileInfo = FileClientFacade.load(fileId);
        List<FileInfo> fileInfos = FileClientFacade.queryByFileMd5(fileInfo.getFileMd5());
        if (CollUtil.isNotEmpty(fileInfos) && fileInfos.size()>1){
            // 多余一个绑定到相同的md5文件上,仅删除文件信息即可
            FileClientFacade.delete(fileId);
            return;
        }
        // 只有一个绑定到相同的md5文件上,删除文件信息,文件MD5信息,文件信息
        FileMd5 fileMd5 = FileMd5ClientFacade.loadByMd5(fileInfo.getFileMd5());
        FileClientFacade.delete(fileId);
        FileMd5ClientFacade.delete(fileMd5.getId());
    }

    /**
     * 下载
     * @param fileId 文件id
     * @return 文件下载地址
     */
    public static FileInfo downloadUrl(String fileId) {
        FileRequestData requestData = new FileRequestData();
        requestData.setFileId(fileId);
        CommonResult<FileInfo> infoCommonResult = FileClientFacade.initFileDownloadPrototype(requestData);
        if (!CommonConstant.QUERY_SUCCESS.equals(infoCommonResult.getResult())){
            throw new BusinessException(infoCommonResult.getResult(),infoCommonResult.getMessage());
        }
        return infoCommonResult.getData();
    }

    /**
     * 下载
     * @param fileId 文件id
     * @return 文件流
     */
    public static InputStream downloadStream(String fileId) {
        FileInfo info = downloadUrl(fileId);
        if (StrUtil.isNotBlank(info.getFileDownloadUrl())){
            throw new BusinessException(ResponseCode.B0300.getCode(),ResponseCode.B0300.getDesc());
        }
        return IoUtil.toStream(HttpUtil.downloadBytes(info.getFileDownloadUrl()));
    }
}
