package com.qmth.teachcloud.common.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.service.AttachmentCommonService;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.util.FileStoreUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 试卷、题卡下载、预览等操作公共服务service impl
 */
@Service
public class AttachmentCommonServiceImpl implements AttachmentCommonService {
    private final static Logger log = LoggerFactory.getLogger(AttachmentCommonServiceImpl.class);

    /**
     * 默认目录
     */
    private static String TEMP_DIR = SystemConstant.TEMP_FILES_DIR + File.separator + System.currentTimeMillis();

    @Resource
    DictionaryConfig dictionaryConfig;

    @Resource
    BasicAttachmentService basicAttachmentService;

    @Resource
    FileStoreUtil fileStoreUtil;

    /**
     * 文件预览
     *
     * @param path 预览路径
     * @return String
     */
    @Override
    public String previewFile(String path) {
        String url;
        JSONObject jsonObject = JSONObject.parseObject(path);
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadFileEnum = UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));
        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            filePath = SystemConstant.getLocalFilePath(filePath);
            url = hostUrl + File.separator + filePath;
        } else {
            url = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
        }
        return url;
    }

    /**
     * 文件预览
     *
     * @param path     附件路径
     * @param type     保存类型：本地、OSS
     * @param isExpire url是否带过期时间
     * @return String
     */
    @Override
    public String previewFile(String path, String type, Boolean isExpire) {
        if (StringUtils.isBlank(path)) {
            return null;
        }

        String pathUrl;
        if (Objects.equals(type, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            path = SystemConstant.getLocalFilePath(path);
            pathUrl = hostUrl + File.separator + path;
        } else {
            pathUrl = fileStoreUtil.getPrivateUrl(path, fileStoreUtil.getUploadEnumByPath(path).getFssType());

        }
        return pathUrl;
    }

    /**
     * 文件预览
     *
     * @param attachmentId 附件ID
     * @param isExpire     url是否带过期时间
     * @return String
     */
    @Override
    public Map<String, String> previewFile(Long attachmentId, Boolean isExpire) {
        BasicAttachment attachment = basicAttachmentService.getById(attachmentId);
        if (attachment == null) {
            return null;
        }

        Map<String, String> map = new HashMap<>();

        String pathUrl;
        JSONObject jsonObject = JSONObject.parseObject(attachment.getPath());
        String attachmentType = (String) jsonObject.get(SystemConstant.TYPE);
        String filePath = (String) jsonObject.get(SystemConstant.PATH);
        UploadFileEnum uploadFileEnum = jsonObject.get(SystemConstant.UPLOAD_TYPE).toString().contains(UploadFileEnum.HTML.name()) ? UploadFileEnum.HTML : UploadFileEnum.valueOf((String) jsonObject.get(SystemConstant.UPLOAD_TYPE));

        if (Objects.equals(attachmentType, SystemConstant.LOCAL)) {
            String hostUrl = SystemConstant.getLocalFileHost(dictionaryConfig.sysDomain().getFileHost());
            filePath = SystemConstant.getLocalFilePath(filePath);
            pathUrl = hostUrl + File.separator + filePath;
        } else {
            pathUrl = fileStoreUtil.getPrivateUrl(filePath, uploadFileEnum.getFssType());
        }
        map.put("url", pathUrl);
        if (attachment.getType().equals(".html")) {
            String htmlMd5 = (String) jsonObject.get("htmlMd5");
            map.put("md5", htmlMd5);
        } else {
            map.put("md5", attachment.getMd5());
        }
        return map;
    }

    @Override
    public File downloadFile(String rootPath, String fileName, Long attachmentId) throws Exception {
        BasicAttachment basicAttachment = basicAttachmentService.getById(attachmentId);
        return downloadFile(rootPath, fileName, basicAttachment);
    }

    @Override
    public File downloadFile(String rootPath, String fileName, BasicAttachment basicAttachment) throws Exception {
        if (basicAttachment == null) {
            throw ExceptionResultEnum.ERROR.exception("附件信息不存在");
        }
        JSONObject object = JSONObject.parseObject(basicAttachment.getPath());
        String filePath = object.getString(SystemConstant.PATH);
        String type = object.getString(SystemConstant.TYPE);
        UploadFileEnum uploadType = Enum.valueOf(UploadFileEnum.class, (String) object.get(SystemConstant.UPLOAD_TYPE));

        // 存储路径为空，使用默认值
        rootPath = StringUtils.isNotBlank(rootPath) ? rootPath : TEMP_DIR;
        // 存储文件名为空，使用默认值
        fileName = StringUtils.isNotBlank(fileName) ? fileName : UUID.fastUUID() + basicAttachment.getType();
        // 存储文件类型与附件类型不一样，默认改用附件类型
        if (!fileName.endsWith(basicAttachment.getType())) {
            fileName = UUID.fastUUID() + basicAttachment.getType();
        }

        // oss存储
        if (type.equals(SystemConstant.OSS)) {
            File localPath = new File(rootPath, fileName);
            try {
                return fileStoreUtil.ossDownload(filePath, localPath.getPath(), uploadType.getFssType());
            } catch (IOException e) {
                throw ExceptionResultEnum.ERROR.exception("从OSS上下载文件失败");
            }
        } else {
            File file = new File(filePath);
            if (!file.exists()) {
                throw ExceptionResultEnum.ERROR.exception("本地文件不存在");
            }
            return file;
        }
    }

    @Override
    public void zipFiles(HttpServletResponse response, String filePath, String zipName, List<File> files) {
        filePath = StringUtils.isNotBlank(filePath) ? filePath : TEMP_DIR;
        File rootFile = new File(filePath);
        // 创建保存目录
        if (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File zipFile = null;
        try {
            zipName = StringUtils.isNotBlank(zipName) ? zipName : UUID.fastUUID() + ".zip";
            if (!zipName.endsWith(".zip")) {
                throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
            }
            zipFile = FileUtil.file(filePath, zipName);
            // 压缩文件
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            File[] srcFiles = files.toArray(new File[0]);
            ZipUtil.zip(zipFile, true, srcFiles);
            outputFile(response, zipFile, zipName);
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("下载失败");
        } finally {
            // 删除zip文件
            FileUtil.del(zipFile);
            // 删除压缩内容
            FileUtil.del(filePath);
        }
    }

    @Override
    public void zipFiles(HttpServletResponse response, String filePath, String zipName) {
        File rootFile = new File(filePath);
        // 创建保存目录
        if (!rootFile.exists()) {
            throw ExceptionResultEnum.ERROR.exception("根目录不存在");
        }
        File zipFile = null;
        try {
            zipName = StringUtils.isNotBlank(zipName) ? zipName : UUID.fastUUID() + ".zip";
            if (!zipName.endsWith(".zip")) {
                throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
            }
            zipFile = FileUtil.file(TEMP_DIR, zipName);
            // 压缩文件
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            ZipUtil.zip(filePath, zipFile.getAbsolutePath(), true);
            outputFile(response, zipFile, zipName);
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("下载失败");
        } finally {
            // 删除zip文件
            FileUtil.del(zipFile);
            // 删除压缩内容
            FileUtil.del(filePath);
        }
    }


    public static void outputFile(HttpServletResponse response, File file, String fileName) {
        try {
            if (!file.exists()) {
                response.sendError(404, "File not found!");
            }

            BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
            byte[] buf = new byte[1024];
            int len = 0;

            String fName = URLEncoder.encode(fileName, "UTF-8");

            response.reset();
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename=" + fName);

            OutputStream outStream = response.getOutputStream();

            while ((len = br.read(buf)) > 0) {
                outStream.write(buf, 0, len);
            }

            br.close();
            outStream.close();
        } catch (IOException e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
    }
}
