package com.artfess.file.persistence.manager.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.annotation.Resource;

import com.artfess.file.params.FileStorageConfigDTO;
import com.artfess.file.params.FlowUploadPropertiesStorageDTO;
import com.artfess.file.persistence.manager.FileConfigManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.artfess.base.attachment.AttachmentService;
import com.artfess.base.attachment.AttachmentServiceFactory;
import com.artfess.base.context.BaseContext;
import com.artfess.base.exception.BaseException;
import com.artfess.base.feign.UCFeignService;
import com.artfess.base.handler.MultiTenantHandler;
import com.artfess.base.handler.MultiTenantIgnoreResult;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.model.CommonResult;
import com.artfess.base.util.AppUtil;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.FileUtil;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.base.util.UniqueIdUtil;
import com.artfess.base.util.ZipUtil;
import com.artfess.base.util.time.TimeUtil;
import com.artfess.file.attachmentService.FtpAttachmentServiceImpl;
import com.artfess.file.model.DefaultFile;
import com.artfess.file.model.FlowUploadProperties;
import com.artfess.file.config.UploadResult;
import com.artfess.file.persistence.dao.FileDao;
import com.artfess.file.persistence.manager.FileManager;
import com.artfess.file.persistence.manager.FlowUploadPropertiesManager;
import com.artfess.file.util.AppFileUtil;
import com.artfess.uc.api.model.IUser;
import com.artfess.uc.api.service.IUserService;

@Service("fileManager")
public class FileManagerImpl extends BaseManagerImpl<FileDao, DefaultFile> implements FileManager {
    @Resource
    UCFeignService ucFeignService;
    @Resource
    IUserService userService;
    @Resource
    BaseContext baseContext;
    @Resource
    FileConfigManager fileConfigManager;

    private AttachmentService attachmentService;

    // 初始化当前附件处理器
    private void initCurrentHandler(String propertiesId) throws Exception {
        AttachmentServiceFactory attachmentHandlerFactory = AppUtil.getBean(AttachmentServiceFactory.class);
        attachmentService = attachmentHandlerFactory.getCurrentServices(AppFileUtil.getSaveType(propertiesId));
    }

    // 初始化当前附件处理器
    private void initCurrentHandlerByBizCode(String bizCode) throws Exception {
        AttachmentServiceFactory attachmentHandlerFactory = AppUtil.getBean(AttachmentServiceFactory.class);
        attachmentService = attachmentHandlerFactory.getCurrentServices(AppFileUtil.getFileSaveTypeByConfig(bizCode));
    }

    @Override
    public List<DefaultFile> getAllByExt(String[] allowFiles) {
        return baseMapper.getAllByExt(allowFiles);
    }

    @Override
    @Transactional
    public void delSysFileByIds(String[] ids) throws Exception {
        String propertiesId = "";
        if (BeanUtils.isNotEmpty(ids) && ids.length > 0) {
            DefaultFile file = this.get(ids[0]);
            if (BeanUtils.isNotEmpty(file)) {
                propertiesId = file.getProp6();
            }
        }
        initCurrentHandler(propertiesId);
        for (String id : ids) {
            DefaultFile def = this.get(id);
            attachmentService.remove(def, BeanUtils.isNotEmpty(def) ? def.getProp6() : "");
            baseMapper.deleteById(id);
        }
    }

    @Override
    public UploadResult UploadFileForConfig(DefaultFile file, List<MultipartFile> files, String bizCode, IUser currentUser) throws Exception {
        Iterator<MultipartFile> it = files.iterator();
        initCurrentHandlerByBizCode(bizCode);
        FileStorageConfigDTO fileStorageConfig = fileConfigManager.getFileConfigByCode(bizCode);
        String fileFormates = fileStorageConfig.getFileKinds();
        Double allowSize = fileStorageConfig.getAllowSize();
        int allowMultiple = fileStorageConfig.getAllowMultiple();
        UploadResult result = new UploadResult();
        if (allowMultiple == 0 && files.size() > 1) {
            result.setSuccess(false);
            result.setMessage("系统只能上传一个附件！");
            return result;
        }

        short isdel = 0;
        while (it.hasNext()) {
            Boolean isAdd = false;
            String oldFilePath = "";
            DefaultFile sysFile;
            if (StringUtil.isNotEmpty(file.getId())) {
                sysFile = this.get(file.getId());
                oldFilePath = sysFile.getFilePath();
            } else {
                // 新增的上传文件
                isAdd = true;
                sysFile = new DefaultFile();
                // 生成新的文件ID
                sysFile.setId(UniqueIdUtil.getSuid());
            }
            MultipartFile f = it.next();
            if (StringUtil.isNotEmpty(file.getFileName())) {
                if (!file.getFileName().equals(f.getName())) {
                    throw new RuntimeException("上传名称与文件名称不符");
                }
            }
            String oriFileName = f.getOriginalFilename();
            String extName = FileUtil.getFileExt(oriFileName);

            //文件格式要求
            if (StringUtil.isNotEmpty(fileFormates)) {
                //不符合文件格式要求的就标志为false
                List<String> typeList = Arrays.asList(fileFormates.split(","));
                for (int i = 0; i < typeList.size(); i++) {
                    if (StringUtil.isNotEmpty(typeList.get(i))) {
                        typeList.set(i, typeList.get(i).toLowerCase());
                    }
                }
                if (typeList.indexOf(extName) < 0 && typeList.indexOf("." + extName) < 0) {
                    result.setSuccess(false);
                    result.setMessage("系统不允许该类型文件的上传！:" + extName);
                    return result;
                }
            }

            if(allowSize!=null && allowSize>0d){
                long len = f.getSize();
                double fileSize = (double) len / 1048576;
                if(fileSize>allowSize){
                    result.setSuccess(false);
                    result.setMessage("上传文件【"+oriFileName+"】大小已超过系统限制："+fileSize+"MB！" );
                    return result;
                }
            }

            String fileName = sysFile.getId() + "." + extName;
            String filePath = "";

            String creatorAccount = DefaultFile.FILE_UPLOAD_UNKNOWN;
            // 当前用户的信息
            if (currentUser != null) {
                sysFile.setCreateBy(currentUser.getUserId());
                sysFile.setCreatorName(currentUser.getFullname());
                creatorAccount = currentUser.getAccount();
            } else {
                sysFile.setCreatorName(creatorAccount);
            }

            if ("pictureShow".equals(sysFile.getFileType())) {
                filePath = AppFileUtil.createFilePath(creatorAccount + File.separator + "pictureShow", fileName);
            } else {
                filePath = AppFileUtil.createFilePath(currentUser.getAccount(), fileName);
            }
            // 附件名称
            sysFile.setFileName(oriFileName.lastIndexOf('.') == -1 ? oriFileName : oriFileName.substring(0, oriFileName.lastIndexOf('.')));
            sysFile.setFilePath(filePath);
            sysFile.setBizCode(bizCode);
            // 上传时间
            sysFile.setCreateTime(LocalDateTime.now());
            // 扩展名
            sysFile.setExtensionName(extName);
            // 字节总数
            sysFile.setByteCount(f.getSize());
            // 说明

            sysFile.setIsDel(isdel);
            sysFile.setNote(FileUtil.getSize(f.getSize()));
            sysFile.setProp6(fileStorageConfig.getStorageId());

            sysFile.setStoreType(fileStorageConfig.getUploadType());
            // 总的字节数

            if (isAdd) {
                sysFile.setBytes(f.getBytes());
                attachmentService.upload(sysFile, f.getInputStream(), BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                if (!fileStorageConfig.getUploadType().equals(DefaultFile.SAVE_TYPE_DTABASE)) {
                    sysFile.setBytes(null);
                }
                super.create(sysFile);
            } else {
                attachmentService.upload(sysFile, f.getInputStream(), BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                this.update(sysFile);
                boolean tag = true;
                String newFilePath = sysFile.getFilePath();
                if (StringUtil.isNotEmpty(newFilePath) && StringUtil.isNotEmpty(oldFilePath)) {
                    if (newFilePath.trim().equals(oldFilePath.trim())) {
                        tag = false;
                    }
                }
                // 修改了文件的存放路径，需要删除之前路径下的文件
                if (tag) {
                    sysFile.setFilePath(oldFilePath);
                    attachmentService.remove(sysFile, BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                }
            }
            result.setSuccess(true);
            result.setFileId(sysFile.getId());
            result.setFileName(oriFileName);
            result.setSize(sysFile.getByteCount());
            result.setUsername(sysFile.getCreatorName());
        }
        return result;
    }

    @Override
    @Transactional
    public UploadResult uploadFile(DefaultFile file, List<MultipartFile> files, String fileFormates, IUser currentUser, String flowKey) throws Exception {
        Iterator<MultipartFile> it = files.iterator();
        initCurrentHandler(flowKey);
        UploadResult result = new UploadResult();
        boolean mark = true;
        short isdel = 0;
        while (it.hasNext()) {
            Boolean isAdd = false;
            String oldFilePath = "";
            DefaultFile sysFile;
            if (StringUtil.isNotEmpty(file.getId())) {
                sysFile = this.get(file.getId());
                oldFilePath = sysFile.getFilePath();
            } else {
                // 新增的上传文件
                isAdd = true;
                sysFile = new DefaultFile();
                // 生成新的文件ID
                sysFile.setId(UniqueIdUtil.getSuid());
            }
            MultipartFile f = it.next();
            if (StringUtil.isNotEmpty(file.getFileName())) {
                if (!file.getFileName().equals(f.getName())) {
                    throw new RuntimeException("上传名称与文件名称不符");
                }
            }
            String oriFileName = f.getOriginalFilename();
            String extName = FileUtil.getFileExt(oriFileName);
            //文件格式要求
            if (StringUtil.isNotEmpty(fileFormates)) {
                //不符合文件格式要求的就标志为false
                List<String> typeList = Arrays.asList(fileFormates.split(","));
                for (int i = 0; i < typeList.size(); i++) {
                    if (StringUtil.isNotEmpty(typeList.get(i))) {
                        typeList.set(i, typeList.get(i).toLowerCase());
                    }
                }
                if (typeList.indexOf(extName) < 0 && typeList.indexOf("." + extName) < 0) {
                    mark = false;
                }
            }
            if (mark) {
                String fileName = sysFile.getId() + "." + extName;
                String filePath = "";

                String creatorAccount = DefaultFile.FILE_UPLOAD_UNKNOWN;
                // 当前用户的信息
                if (currentUser != null) {
                    sysFile.setCreateBy(currentUser.getUserId());
                    sysFile.setCreatorName(currentUser.getFullname());
                    creatorAccount = currentUser.getAccount();
                } else {
                    sysFile.setCreatorName(creatorAccount);
                }
                if ("pictureShow".equals(sysFile.getFileType())) {
                    filePath = AppFileUtil.createFilePath(creatorAccount + File.separator + "pictureShow", fileName);
                } else {
                    filePath = AppFileUtil.createFilePath(currentUser.getAccount(), fileName);
                }
                // 附件名称
                sysFile.setFileName(oriFileName.lastIndexOf('.') == -1 ? oriFileName : oriFileName.substring(0, oriFileName.lastIndexOf('.')));
                sysFile.setFilePath(filePath);
                // 上传时间
                sysFile.setCreateTime(LocalDateTime.now());
                // 扩展名
                sysFile.setExtensionName(extName);
                // 字节总数
                sysFile.setByteCount(f.getSize());
                // 说明

                sysFile.setIsDel(isdel);
                sysFile.setNote(FileUtil.getSize(f.getSize()));

                //流程key
                if (StringUtil.isNotEmpty(flowKey)) {
                    FlowUploadPropertiesManager uploadPropertiesManager = AppUtil.getBean(FlowUploadPropertiesManager.class);
                    FlowUploadPropertiesStorageDTO uploadProperties = uploadPropertiesManager.getByFlowKey(flowKey);
                    if (BeanUtils.isNotEmpty(uploadProperties)) {
                        sysFile.setProp6(uploadProperties.getId());
                    }
                }

                String saveType = AppFileUtil.getSaveType(flowKey);
                sysFile.setStoreType(saveType);
                // 总的字节数

                if (isAdd) {
                    sysFile.setBytes(f.getBytes());
                    attachmentService.upload(sysFile, f.getInputStream(), BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                    if (!saveType.equals(DefaultFile.SAVE_TYPE_DTABASE)) {
                        sysFile.setBytes(null);
                    }
                    super.create(sysFile);
                } else {
                    attachmentService.upload(sysFile, f.getInputStream(), BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                    this.update(sysFile);
                    boolean tag = true;
                    String newFilePath = sysFile.getFilePath();
                    if (StringUtil.isNotEmpty(newFilePath) && StringUtil.isNotEmpty(oldFilePath)) {
                        if (newFilePath.trim().equals(oldFilePath.trim())) {
                            tag = false;
                        }
                    }
                    // 修改了文件的存放路径，需要删除之前路径下的文件
                    if (tag) {
                        sysFile.setFilePath(oldFilePath);
                        attachmentService.remove(sysFile, BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
                    }
                }
                result.setSuccess(true);
                result.setFileId(sysFile.getId());
                result.setFileName(oriFileName);
                result.setSize(sysFile.getByteCount());
                result.setUsername(sysFile.getCreatorName());

            } else {
                result.setSuccess(false);
                result.setMessage("系统不允许该类型文件的上传！:" + extName);
            }
        }
        return result;
    }

    @Override
    public DefaultFile downloadFile(String fileId, OutputStream outStream) throws Exception {
        DefaultFile sysFile = this.get(fileId);
        initCurrentHandler(BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
        if (BeanUtils.isEmpty(sysFile)) {
            return null;
        }//特殊场景，附件上传方式是ftp，word套打生成的文件是磁盘存储，下载套打文件时特殊处理
        else if (attachmentService instanceof FtpAttachmentServiceImpl && DefaultFile.SAVE_TYPE_FOLDER.equals(sysFile.getStoreType())) {
            AttachmentServiceFactory attachmentHandlerFactory = AppUtil.getBean(AttachmentServiceFactory.class);
            attachmentService = attachmentHandlerFactory.getCurrentServices(DefaultFile.SAVE_TYPE_FOLDER);
        }
        attachmentService.download(sysFile, outStream, BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
        return sysFile;
    }

    @Override
    @Transactional
    public void uploadFile(DefaultFile file, InputStream inputStream) throws Exception {
        initCurrentHandler(BeanUtils.isNotEmpty(file) ? file.getProp6() : "");
        String storeType = file.getStoreType();
        if (StringUtil.isEmpty(file.getId())) {
            file.setId(UniqueIdUtil.getSuid());
        }
        attachmentService.upload(file, inputStream, BeanUtils.isNotEmpty(file) ? file.getProp6() : "");
        if (StringUtil.isEmpty(storeType)) {
            storeType = AppFileUtil.getSaveType(BeanUtils.isNotEmpty(file) ? file.getProp6() : "");
            file.setStoreType(storeType);
        }
        if (!DefaultFile.SAVE_TYPE_DTABASE.equals(storeType)) {
            file.setBytes(null);
        }
        super.create(file);
    }

    @Override
    @Transactional
    public void setXbTypeId(List<String> fileId, String xbTypeId, String type) throws Exception {
        baseMapper.setXbTypeId(fileId, xbTypeId, type);
    }

    @Override
    @Transactional
    public void updateFileExtraProp(List<DefaultFile> files) {
        if (BeanUtils.isNotEmpty(files)) {
            for (DefaultFile defaultFile : files) {
                baseMapper.updateExtraProps(defaultFile);
            }
        }
    }

    @Override
    public byte[] getFileBytesById(String fileId) throws Exception {
        DefaultFile sysFile = this.get(fileId);
        initCurrentHandler(BeanUtils.isNotEmpty(sysFile) ? sysFile.getProp6() : "");
        if (BeanUtils.isEmpty(sysFile)) {
            return null;
        }
        return attachmentService.getFileBytes(sysFile);
    }

    @Override
    public DefaultFile get(Serializable id) {
        DefaultFile file = null;
        try (MultiTenantIgnoreResult setThreadLocalIgnore = MultiTenantHandler.setThreadLocalIgnore()) {
            file = super.get(id);
        } catch (Exception e) {
            throw new BaseException(e.getMessage(), e);
        }
        return file;
    }

    @Override
    public void downloadFileToPath(DefaultFile file, String path) throws Exception {
        initCurrentHandler(BeanUtils.isNotEmpty(file) ? file.getProp6() : "");
        File dfile = new File(path);
        if (!dfile.exists()) {
            if (BeanUtils.isNotEmpty(dfile.getParentFile()) && !dfile.getParentFile().exists()) {
                dfile.getParentFile().mkdir();
            }
            OutputStream out = new FileOutputStream(dfile);
            attachmentService.download(file, out, BeanUtils.isNotEmpty(file) ? file.getProp6() : "");
            out.flush();
            out.close();
        }
    }

    @Override
    public CommonResult<String> importSignature(MultipartFile file,
                                                boolean isCover) {
        String rootRealPath = "";
        CommonResult<String> message = new CommonResult<String>(true, "导入成功！");
        try {
            String unZipDir = TimeUtil.getCurrentTimeMillis() + "_" + baseContext.getCurrentUserId();
            rootRealPath = (FileUtil.getIoTmpdir() + "attachFiles/unZip/" + unZipDir).replace("/", File.separator);
            //建立临时文件夹，存放文件
            File folder = new File(rootRealPath);
            if (!folder.exists()) {
                folder.mkdirs();
            }
            ZipUtil.unZipFile(file, rootRealPath);
            File ignatureFloder = new File(rootRealPath);        //获取其file对象
            File[] fs = ignatureFloder.listFiles();    //遍历path下的文件和目录，放在File数组中
            IUser user = null;
            String account = baseContext.getCurrentUserAccout();
            if (StringUtil.isNotEmpty(account)) {
                user = userService.getUserByAccount(account);
            }
            ArrayNode accountFiles = JsonUtil.getMapper().createArrayNode();
            // 创建一个线程池
            ExecutorService pool = Executors.newFixedThreadPool(fs.length);
            FileManager fileManager = AppUtil.getBean(FileManager.class);
            // 创建多个有返回值的任务
            List<Future> list = new ArrayList<Future>();
            for (File signatureFile : fs) {
                if (!signatureFile.isDirectory() && signatureFile.getName().endsWith(".png")) {//如果是.png的图片文件则处理
                    Callable c = new MyCallable(signatureFile, user, fileManager);
                    // 执行任务并获取Future对象
                    Future f = pool.submit(c);
                    list.add(f);
                }
            }
            for (Future f : list) {
                UploadResult result = (UploadResult) f.get();
                if (result.isSuccess()) {
                    ObjectNode accountFile = JsonUtil.getMapper().createObjectNode();
                    String[] names = result.getFileName().split("\\.");
                    accountFile.put("account", names[0]);
                    accountFile.put("fileId", result.getFileId());
                    accountFiles.add(accountFile);
                }
            }
            if (accountFiles.size() > 0) {
                ObjectNode signatureData = JsonUtil.getMapper().createObjectNode();
                signatureData.put("repeatConver", isCover);
                signatureData.set("signatureList", accountFiles);
                CommonResult<String> result = ucFeignService.saveSignatureBatch(signatureData);
                //如果签章处理失败，则删除已上传的附件
                if (!result.getState()) {
                    String[] ids = new String[signatureData.size()];
                    for (int i = 0; i < accountFiles.size(); i++) {
                        ids[i] = accountFiles.get(i).get("fileId").asText();
                    }
                    this.delSysFileByIds(ids);
                    return new CommonResult<String>(false, "导入失败：" + result.getMessage());
                }
            }
        } catch (Exception e) {
            message = new CommonResult<String>(false, "导入失败:" + e.getMessage());
        } finally {
            File fileDir = new File(rootRealPath);
            if (fileDir.exists()) {
                FileUtil.deleteDir(fileDir); // 删除解压后的目录
            }
        }
        return message;
    }

    class MyCallable implements Callable<Object> {
        private Logger logger = LoggerFactory.getLogger(FileManagerImpl.class);
        private File file;
        private IUser user;
        private FileManager fileManager;

        MyCallable(File file, IUser user, FileManager fileManager) {
            this.file = file;
            this.user = user;
            this.fileManager = fileManager;
        }

        @Override
        public Object call() throws Exception {
            logger.info(">>>" + file.getName() + "签章附件上传");
            LocalDateTime dateTmp1 = LocalDateTime.now();
            UploadResult result = upload();
            Thread.sleep(200);
            LocalDateTime dateTmp2 = LocalDateTime.now();
            long time = TimeUtil.getTimeMillis(dateTmp2) - TimeUtil.getTimeMillis(dateTmp1);
            logger.info(">>>" + file.getName() + "签章附件上传完成; 花费时间为： " + time);
            return result;
        }

        private UploadResult upload() {
            try {
                FileManager fileManager = AppUtil.getBean(FileManager.class);
                MultipartFile multipartFile = FileUtil.fileToMultipartFile(file);
                List<MultipartFile> files = new ArrayList<MultipartFile>();
                files.add(multipartFile);
                DefaultFile file = new DefaultFile();
                return fileManager.uploadFile(file, files, null, user, "");
            } catch (Exception e) {
                logger.info(">>>" + file.getName() + "签章附件上传失败： " + e.getMessage());
            }
            return null;
        }

    }

}
