package com.microservices.file.service.impl;

import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.ServletUtils;
import com.microservices.common.core.utils.html.EscapeUtil;
import com.microservices.file.service.ISysFileInfoAsyncService;
import com.microservices.file.service.ISysFileInfoService;
import com.microservices.file.utils.CustomExecutorFactory;
import com.microservices.file.utils.ZipUtils;
import com.microservices.system.api.domain.SysFileInfo;
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.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;

/**
 * @author OTTO
 */
@Service
public class SysFileInfoAsyncServiceImpl implements ISysFileInfoAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(SysFileInfoAsyncServiceImpl.class);

    @Lazy
    @Autowired
    private ISysFileInfoService sysFileInfoService;

    /**
     * 上传文件存储在本地的根路径
     */
    @Value("${file.path}")
    private String localFilePath;

    @Override
    public void asyncPackagedFile(String fileIdentifier, HashMap<String, String> packagedStructure, String zipFileName, String type, String hierarchy) {
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            Path localPath = Paths.get(localFilePath);
            // 输出目录
            String datePath = DateUtils.datePath();
            Path packagedPath = localPath
                    .resolve(type)
                    .resolve(hierarchy)
                    .resolve(datePath);
            // 构建打包的临时工作目录
            Path tempPackagedPath = packagedPath
                    .resolve(zipFileName);
            try {
                try {
                    // 将所有文件根据层级结构拷贝到临时目录
                    packagedStructure.forEach((packagedFilePathStr, fileSource) -> {
                        String packagedDirPathStr = Paths.get(ServletUtils.urlDecode(packagedFilePathStr)).getParent().toString();
                        try {
                            // 创建文件对应目录
                            Path packagedDirPath = tempPackagedPath.resolve(packagedDirPathStr);
                            Files.createDirectories(packagedDirPath);
                            // 文件标识长度为8位
                            if (fileSource.length() == 8) {
                                SysFileInfo fileInfo = sysFileInfoService.selectSysFileInfoByFileIdentifier(fileSource);
                                String filePath = localFilePath + fileInfo.getFilePath();
                                File file = new File(filePath);
                                if (!file.exists()) {
                                    throw new IOException("该文件不存在");
                                }
                                // 拷贝文件到打包目录
                                FileInputStream fileInputStream = new FileInputStream(file);
                                Files.copy(fileInputStream, packagedDirPath.resolve(fileInfo.getFileOriginName()));
                            } else {
                                String encodeFileName = fileSource.substring(fileSource.lastIndexOf('/') + 1);
                                String fileName = ServletUtils.urlDecode(ServletUtils.urlDecode(encodeFileName));
                                Path packagedFilePath = packagedDirPath.resolve(fileName);
                                org.apache.commons.io.FileUtils.copyURLToFile(new URL(fileSource), packagedFilePath.toFile());
                            }
                        } catch (IOException e) {
                            logger.error("打包文件时出现异常，需压缩文件处理失败:{}", e.getMessage());
                            throw new ServiceException("打包文件时出现异常，需压缩文件处理失败！");
                        }
                    });
                    String fullZipFileName = zipFileName + ".zip";
                    Path zipFilePath = packagedPath.resolve(fullZipFileName);
                    ZipUtils.toZip(tempPackagedPath.toString(), Files.newOutputStream(zipFilePath), true);
                    File zipFile = zipFilePath.toFile();
                    if (!zipFile.exists()) {
                        throw new ServiceException("打包文件时出现异常：文件压缩失败");
                    }
                    String filePath = EscapeUtil.removeExtraSlashOfUrl("/" + type + "/" + hierarchy + "/" + datePath + "/" + fullZipFileName);
                    SysFileInfo sysFileInfo = new SysFileInfo(fileIdentifier, zipFile, filePath);
                    sysFileInfoService.insertSysFileInfo(sysFileInfo);
                } finally {
                    //删除临时目录
                    org.apache.commons.io.FileUtils.deleteDirectory(tempPackagedPath.toFile());
                }
            } catch (IOException e) {
                logger.error("打包文件时出现异常:{}", e.getMessage());
                throw new ServiceException("打包文件时出现异常！");
            }
        });
    }
}
