package com.artfess.file.attachmentService;

import com.artfess.base.attachment.Attachment;
import com.artfess.base.attachment.AttachmentService;
import com.artfess.base.exception.BaseException;
import com.artfess.base.util.AppUtil;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.FileUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.file.config.FileUploadSetting;
import com.artfess.file.params.FlowUploadPropertiesStorageDTO;
import com.artfess.file.persistence.manager.FlowUploadPropertiesManager;
import com.artfess.file.util.AppFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@Slf4j
@Service
public class FolderAttachmentServiceImpl implements AttachmentService {

    public FolderAttachmentServiceImpl() {

    }

    public void remove(Attachment attachment, String propertiesId) throws Exception {
        String attachPath = getAttachPath(propertiesId, attachment);
        String filePath = attachment.getFilePath();
        if (!attachment.getEntryptName()) {
            filePath = filePath.replace(attachment.getId(), attachment.getFileName());
        }
        String fullPath = attachPath + File.separator + filePath;
        // 删除文件
        FileUtil.deleteFile(fullPath);
    }

    @Override
    public void upload(Attachment attachment, InputStream inputStream, String propertiesId) throws Exception {
        String filePath = attachment.getFilePath();
        String attachPath = getAttachPath(propertiesId, attachment);
        if (!attachment.getEntryptName()) {
            filePath = filePath.replace(attachment.getId(), attachment.getFileName());
        }
        filePath = attachPath + File.separator + filePath;
        if (BeanUtils.isNotEmpty(inputStream)) {
            FileUtil.createFolderFile(filePath);
            FileUtil.writeFile(filePath, inputStream);
        } else {
            FileUtil.writeByte(filePath, attachment.getBytes());
        }
    }

    public void download(Attachment attachment, OutputStream outStream, String propertiesId)
            throws Exception {
        String filePath = null;
        if(StringUtil.isEmpty(attachment.getZoneTotal()) || "0".equals(attachment.getZoneTotal())) {
            filePath = getAttachPath(propertiesId,attachment);
            String attachPath = getAttachPath(propertiesId,attachment);
            if(!attachment.getEntryptName()){
                filePath = filePath.replace(attachment.getId(), attachment.getFileName());
            }
            filePath=attachPath+File.separator+filePath;
        }else{
            FileUploadSetting fileUploadSetting = AppUtil.getBean(FileUploadSetting.class);
            String basepath = fileUploadSetting.getBasepath();
            filePath = basepath + File.separator + attachment.getMd5Value() + File.separator + attachment.getFileName();
        }
        String fullPath = filePath.replace("/", File.separator);
        File file = new File(fullPath);
        if (file.exists()) {
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(fullPath);
                byte[] b = new byte[1024];
                int i = 0;
                while ((i = inputStream.read(b)) > 0) {
                    outStream.write(b, 0, i);
                }
                outStream.flush();
            } catch (Exception e) {
                throw e;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                    inputStream = null;
                }
                if (outStream != null) {
                    outStream.close();
                    outStream = null;
                }
            }
        } else {
            throw new RuntimeException("该附件不存在");
        }
    }


    @Override
    public String getStoreType() {
        return "folder";
    }

    @Override
    public boolean chekckFile(Attachment attachment, String propertiesId) {
        String filePath = null;
        if(StringUtil.isEmpty(attachment.getZoneTotal()) || "0".equals(attachment.getZoneTotal())) {
            filePath = getAttachPath(propertiesId,attachment);
            String attachPath = getAttachPath(propertiesId,attachment);
            if(!attachment.getEntryptName()){
                filePath = filePath.replace(attachment.getId(), attachment.getFileName());
            }
            filePath=attachPath+File.separator+filePath;
        }else{
            FileUploadSetting fileUploadSetting = AppUtil.getBean(FileUploadSetting.class);
            String basepath = fileUploadSetting.getBasepath();
            filePath = basepath + File.separator + attachment.getMd5Value() + File.separator + attachment.getFileName();
        }
        String fullPath = filePath.replace("/", File.separator);
        File file = new File(fullPath);
        return file.exists();
    }

    /**
     * 获取文件上传根目录
     *
     * @param propertiesId
     * @return
     */
    private String getAttachPath(String propertiesId, Attachment attachment) {
        FlowUploadPropertiesStorageDTO uploadProperties = getUploadProperties(propertiesId);
        String attachPath = "";
        if (BeanUtils.isNotEmpty(uploadProperties)) {
            attachPath = uploadProperties.getLocation();
            attachment.setEntryptName(uploadProperties.getEncryptName() == 0 ? false : true);
        } else {
            attachPath = AppFileUtil.getAttachPath();
        }
        return attachPath;
    }

    /**
     * 根据配置id获取文件上传配置
     *
     * @param propertiesId
     * @return
     */
    private FlowUploadPropertiesStorageDTO getUploadProperties(String propertiesId) {
        if (StringUtil.isEmpty(propertiesId)) {
            return null;
        }
        FlowUploadPropertiesManager uploadPropertiesManager = AppUtil.getBean(FlowUploadPropertiesManager.class);
        return uploadPropertiesManager.getById(propertiesId);
    }

    @Override
    public byte[] getFileBytes(Attachment sysFile) throws Exception {

        String filePath = sysFile.getFilePath();
        String fullPath = StringUtil.trimSufffix(AppFileUtil.getAttachPath(),
                File.separator)
                + File.separator
                + filePath.replace("/", File.separator);

        File file = new File(fullPath);
        if (file.exists()) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(fullPath);
                byte[] b = new byte[1024];
                int i = 0;
                while ((i = inputStream.read(b)) > 0) {
                    outStream.write(b, 0, i);
                }
                outStream.flush();
                return outStream.toByteArray();
            } catch (Exception e) {
                throw e;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                    inputStream = null;
                }
                if (outStream != null) {
                    outStream.close();
                    outStream = null;
                }
            }
        } else {
            throw new RuntimeException("该附件不存在");
        }
    }

    @Override
    public String initMultiPartUpload(Attachment attachment) {
        //初始化创建文件夹
        FileUploadSetting fileUploadSetting = AppUtil.getBean(FileUploadSetting.class);
        String chunkFolder = fileUploadSetting.getBasepath() + File.separator + attachment.getMd5Value();
        File file = new File(chunkFolder);
        if (!file.exists()) {
            file.mkdirs();
        }

        return attachment.getMd5Value();
    }

    @Override
    public String getChunkUrl(Attachment attachment, Integer partNumber, String uploadId) {
        FileUploadSetting fileUploadSetting = AppUtil.getBean(FileUploadSetting.class);
        String chunkFolder = fileUploadSetting.getBasepath() + File.separator + attachment.getMd5Value();
        return chunkFolder + File.separator + partNumber;
    }

    @Override
    public boolean mergeMultipartUpload(Attachment attachment, String uploadId, int realyPartNumber) {
        log.info("分片合并==================================》");
        // 块文件目录
        FileUploadSetting fileUploadSetting = AppUtil.getBean(FileUploadSetting.class);
        File chunkFolder = new File(fileUploadSetting.getBasepath() + File.separator + attachment.getMd5Value());
        // 合并后的文件
        File mergeFile = new File(fileUploadSetting.getBasepath() + File.separator + attachment.getMd5Value() + File.separator + attachment.getFileName());
        // 取出所有分块文件
        File[] files = chunkFolder.listFiles();
        // 将数组转成list
        List<File> filesList = Arrays.asList(files);
        // 若上传的分片少于实际分片数量，不能合并
        if (filesList.size() < realyPartNumber) {
            // 分片文件不够，不能合并
            log.info(">>>>>>>>>>{}分片文件不够，不能合并", uploadId);
            throw new BaseException("分片文件不够，不能合并！");
        }
        long startTime = System.currentTimeMillis();
        // 对分块文件排序
        Collections.sort(filesList, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                // 将分块文件按文件名称1、2、3、4、5...排序
                return Integer.parseInt(o1.getName()) - Integer.parseInt(o2.getName());
            }
        });
        // 向合并文件写的流
        RandomAccessFile raf_rw = null;
        try {
            raf_rw = new RandomAccessFile(mergeFile, "rw");
            // 缓冲区
            byte[] bytes = new byte[1024];
            // 遍历分块文件
            for (File file : filesList) {
                // 读分块的流
                RandomAccessFile raf_r = new RandomAccessFile(file, "r");
                int len = -1;
                // 从分块中读取数据到缓冲区
                while ((len = raf_r.read(bytes)) != -1) {
                    // 将缓冲区的数据写入合并文件
                    raf_rw.write(bytes, 0, len);
                }
                raf_r.close();
            }
            raf_rw.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}
