package com.qmth.distributed.print.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.tools.io.ZipReader;
import com.qmth.boot.tools.io.ZipWriter;
import com.qmth.distributed.print.business.bean.upgrade.Mainfest;
import com.qmth.distributed.print.business.bean.upgrade.MainfestApp;
import com.qmth.distributed.print.business.bean.upgrade.MainfestScript;
import com.qmth.distributed.print.business.bean.upgrade.result.ClientInstallResult;
import com.qmth.distributed.print.business.bean.upgrade.result.ClientResult;
import com.qmth.distributed.print.business.bean.upgrade.result.ClientUpgradeResult;
import com.qmth.distributed.print.business.entity.ClientUpgrade;
import com.qmth.distributed.print.business.mapper.ClientUpgradeMapper;
import com.qmth.distributed.print.business.service.ClientUpgradeService;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.enums.clientpackage.ClientPackageEnum;
import com.qmth.teachcloud.common.service.FileUploadService;
import com.qmth.teachcloud.common.util.FileUtil;
import com.qmth.teachcloud.common.util.Zip4jUtil;
import okio.Buffer;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xf
 * @since 2024-03-20
 */
@Service
public class ClientUpgradeServiceImpl extends ServiceImpl<ClientUpgradeMapper, ClientUpgrade> implements ClientUpgradeService {

    private static String platform = "WINDOWS";
    private static String MAIN_FEST_JSON = "mainfest.json";

    @Resource
    private FileUploadService fileUploadService;

    @Override
    public void upload(MultipartFile file, String md5, ClientPackageEnum type) {
        File parentDirVar = null;
        try {
            String fileName = FilenameUtils.getName(file.getOriginalFilename());

            if (ClientPackageEnum.INSTALL.equals(type) && !fileName.endsWith(".exe")) {
                throw ExceptionResultEnum.ERROR.exception("安装包只能上传后缀为[.exe]的文件");
            }
            if (ClientPackageEnum.UPGRADE.equals(type) && !fileName.endsWith(".zip")) {
                throw ExceptionResultEnum.ERROR.exception("升级包只能上传后缀为[.zip]的文件");
            }

            String fileMd5 = DigestUtils.md5Hex(file.getBytes());
            if (!Objects.equals(fileMd5, md5)) {
                throw ExceptionResultEnum.MD5_EQUALS_FALSE.exception();
            }

            ClientUpgrade clientUpgrade = this.getByPlatform(platform);
            //安装包
            if (ClientPackageEnum.INSTALL.equals(type)) {
                // 上传
                String filePathName = buildPath(true, UploadFileEnum.UPGRADE.getTitle(), "release", platform) + fileName;
                FilePathVo filePathVo = fileUploadService.uploadFile(file, UploadFileEnum.UPGRADE, filePathName, fileMd5);
                clientUpgrade.setInstallPath(JSON.toJSONString(filePathVo));
                clientUpgrade.setInstallUploadTime(System.currentTimeMillis());
            } else if (ClientPackageEnum.UPGRADE.equals(type)) {
                // 升级包文件上传
                parentDirVar = SystemConstant.getFileTempDirVar(SystemConstant.ZIP_PREFIX);
//                file.transferTo(parentDirVar);
                FileUtils.copyToFile(file.getInputStream(), parentDirVar);
                ZipReader zipReader = new ZipReader(parentDirVar);
                String mainfestJson = "mainfest.json";

                // 读取指定文件内容mainfest.josn
                String mainfestContent = readMainfest(zipReader.read(mainfestJson));
                if (StringUtils.isBlank(mainfestContent)) {
                    throw ExceptionResultEnum.ERROR.exception("读取mainfest.json文件内容失败");
                }
                // 解析mainfest.json内容
                Mainfest mainfest = JSON.parseObject(mainfestContent, Mainfest.class);
                String version = mainfest.getVersion();
                if (StringUtils.isBlank(version)) {
                    throw ExceptionResultEnum.ERROR.exception("version值必填");
                }
                Integer build = mainfest.getBuild();
                if (build == null) {
                    throw ExceptionResultEnum.ERROR.exception("build值必填");
                }
                Integer supportMin = mainfest.getSupportMin();
                if (supportMin == null) {
                    throw ExceptionResultEnum.ERROR.exception("supportMin值必填");
                }
                // 上传
                String filePathName = buildPath(true, UploadFileEnum.UPGRADE.getTitle(), "update", platform, version, String.valueOf(build)) + fileName;
                FilePathVo filePathVo = fileUploadService.uploadFile(file, UploadFileEnum.UPGRADE, filePathName, fileMd5);
                clientUpgrade.setVersion(version);
                clientUpgrade.setBuild(build);
                clientUpgrade.setSupportMin(supportMin);
                clientUpgrade.setUpgradePath(JSON.toJSONString(filePathVo));

                // 上传mainfest.json文件
                String mainfestPathName = buildPath(true, UploadFileEnum.UPGRADE.getTitle(), "update", platform, version, String.valueOf(build)) + mainfestJson;
                FilePathVo mainfestPathVo = fileUploadService.uploadFile(zipReader.read(mainfestJson), UploadFileEnum.UPGRADE, mainfestPathName, DigestUtils.md5Hex(zipReader.read(mainfestJson)));
                clientUpgrade.setMainfestPath(JSON.toJSONString(mainfestPathVo));
                // 上传app目录下文件
                String app = "app";
                for (MainfestApp mainfestApp : mainfest.getApp()) {
                    // 上传
                    uploadUpgradeZipFiles(version, build, zipReader, app, mainfestApp.getName());
                }
                // 上传script目录下文件
                String script = "script";
                MainfestScript mainfestScript = mainfest.getScript();
                uploadUpgradeZipFiles(version, build, zipReader, script, mainfestScript.getBefore());
                uploadUpgradeZipFiles(version, build, zipReader, script, mainfestScript.getAfter());
                for (String includeFileName : mainfestScript.getIncludes()) {
                    uploadUpgradeZipFiles(version, build, zipReader, script, includeFileName);
                }
                // 上传data目录下文件
                String data = "data";
                for (String dataFileName : mainfest.getData()) {
                    uploadUpgradeZipFiles(version, build, zipReader, data, dataFileName);
                }
                clientUpgrade.setUpgradeUploadTime(System.currentTimeMillis());
            } else {
                throw ExceptionResultEnum.ERROR.exception("请选择正确的包类型");
            }
            // 保存或更新
            this.saveOrUpdate(clientUpgrade);
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(type.getName() + "上传失败：" + e.getMessage());
        } finally {
            if (parentDirVar != null) {
                FileUtil.deleteFile(parentDirVar);
            }
        }
    }

    private void uploadUpgradeZipFiles(String version, int build, ZipReader zipReader, String pathType, String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return;
        }
        // 上传
        String filePath = FileUtil.replaceSplit(pathType + File.separator + fileName);
        String dataPathName = buildPath(true, UploadFileEnum.UPGRADE.getTitle(), "update", platform, version, String.valueOf(build), pathType) + fileName;
        try {
            fileUploadService.uploadFile(zipReader.read(filePath), UploadFileEnum.UPGRADE, dataPathName, DigestUtils.md5Hex(zipReader.read(filePath)));
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception(pathType + "目录下文件[" + fileName + "]上传失败");
        }
    }

    /**
     * 升级数据查询
     *
     * @param platform 平台类型
     */
    @Override
    public ClientUpgrade getByPlatform(String platform) {
        QueryWrapper<ClientUpgrade> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ClientUpgrade::getPlatform, platform);
        ClientUpgrade clientUpgrade = this.getOne(queryWrapper);
        if (clientUpgrade == null) {
            clientUpgrade = new ClientUpgrade(platform);
        }
        return clientUpgrade;
    }

    @Override
    public ClientResult getExternalByPlatform(String platform) {
        ClientUpgrade clientUpgrade = this.getByPlatform(platform);
        ClientResult clientResult = new ClientResult();
        ClientInstallResult clientInstallResult = new ClientInstallResult();
        ClientUpgradeResult clientUpgradeResult = new ClientUpgradeResult();
        String prefix = null;
        if (StringUtils.isNotBlank(clientUpgrade.getInstallPath())) {
            prefix = fileUploadService.filePreviewPrefix(clientUpgrade.getInstallPath());
            String installUrl = JSON.parseObject(clientUpgrade.getInstallPath(), FilePathVo.class).getPath();
            clientInstallResult.setUrl(installUrl);
            clientInstallResult.setInstallUploadTime(clientUpgrade.getInstallUploadTime());
            clientInstallResult.setFileName(installUrl.substring(installUrl.lastIndexOf(SystemConstant.ORG_SPLIT) + 1));
        }
        clientResult.setInstall(clientInstallResult);
        if (StringUtils.isNotBlank(clientUpgrade.getMainfestPath())) {
            if (StringUtils.isBlank(prefix)) {
                prefix = fileUploadService.filePreviewPrefix(clientUpgrade.getMainfestPath());
            }
            clientUpgradeResult.setVersion(clientUpgrade.getVersion());
            clientUpgradeResult.setBuild(clientUpgrade.getBuild());
            clientUpgradeResult.setSupportMin(clientUpgrade.getSupportMin());
            String indexUrl = JSON.parseObject(clientUpgrade.getMainfestPath(), FilePathVo.class).getPath();
            clientUpgradeResult.setIndex(indexUrl);
            clientUpgradeResult.setUpgradeUploadTime(clientUpgrade.getUpgradeUploadTime());
        }
        clientResult.setUpgrade(clientUpgradeResult);
        clientResult.setPrefix(prefix);
        return clientResult;
    }

    /**
     * 读取mainfest.json文件
     *
     * @param inputStream 文件流
     */
    private static String readMainfest(InputStream inputStream) {
        try {
            // 读取目标文件的内容
            StringBuilder content = new StringBuilder();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                content.append(new String(buffer, 0, length));
            }
            return content.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 路径拼接
     *
     * @param endSeparator 结尾是否带分隔符
     * @param paths        路径数组
     */
    private String buildPath(boolean endSeparator, String... paths) {
        StringJoiner stringJoiner = new StringJoiner(File.separator);
        for (String path : paths) {
            stringJoiner.add(path);
        }
        String path = stringJoiner.toString();
        if (endSeparator) {
            path = path + File.separator;
        }
        return path;
    }

}
