package org.springblade.modules.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.modules.system.entity.PlatomixSystemFile;
import org.springblade.modules.system.service.PlatomixSystemFileService;
import org.springblade.modules.system.utils.ByteUnitConversionUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文件上传
 */
@RestController
@Api(value = "附件管理controller", tags = {"附件管理接口"})
@RequestMapping("/file")
public class FileController {

    public static final String UPLOADS = "uploads/";
    @Value("${blade.file.uploadPath}")
    private String picDir;
    @Resource
    private BladeRedis bladeRedis;
    @Resource
    private PlatomixSystemFileService platomixSystemFileService;

    @PostMapping("/uploadFile")
    @ApiOperation(value = "上传附件", notes = "上传附件，不大于100M")
    public R uploadFile(@RequestParam(value = "serialNumber", required = false) String serialNumber, MultipartFile file) {
        if (null == file) {
            return R.fail("文件不能为空");
        }
        String oFileName = file.getOriginalFilename();
        String fileSuffix = oFileName.substring(oFileName.lastIndexOf("."));
        if (!".jpg".equalsIgnoreCase(fileSuffix) &&
                !".jpeg".equalsIgnoreCase(fileSuffix) &&
                !".gif".equalsIgnoreCase(fileSuffix) &&
                !".png".equalsIgnoreCase(fileSuffix) &&
                !".pdf".equalsIgnoreCase(fileSuffix) &&
                !".doc".equalsIgnoreCase(fileSuffix) &&
                !".docx".equalsIgnoreCase(fileSuffix) &&
                !".xls".equalsIgnoreCase(fileSuffix) &&
                !".jar".equalsIgnoreCase(fileSuffix) &&
                !".svg".equalsIgnoreCase(fileSuffix) &&
                !".xlsx".equalsIgnoreCase(fileSuffix) &&false) {

            return R.fail("只能上传jpg/jpeg/gif/png/pdf/doc/xls/jar/svg类型的文件");
        }

        if (file.getSize() > 1024 * 1000 * 500) {
            return R.fail("附件不得大于500M");
        }

        String tempFileName = UUID.randomUUID().toString() + fileSuffix;

        File f = new File(picDir + tempFileName);
        try {
            FileUtil.writeFromStream(file.getInputStream(), f);
//            FileUtils.copyInputStreamToFile(file.getInputStream(), f);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (StringUtils.isNotBlank(serialNumber)) {
            SetOperations<String, Object> setOps = bladeRedis.getSetOps();
            setOps.add(serialNumber, UPLOADS + tempFileName);
            bladeRedis.expire(serialNumber, Duration.ofMinutes(10));
        }
        return R.data(UPLOADS + tempFileName, UPLOADS + tempFileName);
    }

    public static void main(String[] args) throws Exception {
        FileInputStream i1 = new FileInputStream(new File("/Users/wangrui/Desktop/flow/导出数据.xlsx"));
        String path = "/Users/wangrui/Desktop/dir1";
        FileUtil.mkdir(path);
        File f2 = new File(path + File.separator + "导出数据2.xlsx");
        FileUtil.writeFromStream(i1, f2);
        FileInputStream i2 = new FileInputStream(new File("/Users/wangrui/Desktop/flow/导出数据.xlsx"));
        File f3 = new File("/Users/wangrui/Desktop/dir5/dir6" + File.separator + "导出数据2.xlsx");
        FileUtil.writeFromStream(i2, f3);
    }

    @PostMapping("/getFileById")
    @ApiOperation(value = " 根据 id 查询文件列表")
    public R getFileById(@RequestBody Set<String> ids) {
        List<String> collect = ids.stream().filter(NumberUtil::isLong).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return R.data(Maps.newHashMap());
        }
        List<PlatomixSystemFile> list = platomixSystemFileService.lambdaQuery()
                .in(PlatomixSystemFile::getId, collect)
                .list();
        //list集合通过 stream转map,key 是PlatomixSystemFile.id
        Map<String, PlatomixSystemFile> map = list.stream().collect(Collectors.toMap(PlatomixSystemFile::getId, a -> a, (k1, k2) -> k1));
        return R.data(map);
    }

    @GetMapping("/getFileInputStreamById/{id}")
    @ApiOperation(value = " 根据 id 查询文件列表")
    public R getFileInputStreamById(@PathVariable("id") String id, HttpServletResponse resp) throws Exception {
        if (StringUtils.isEmpty(id)) {
            return R.fail("文件 id 不能为空!");
        }
        long now = System.currentTimeMillis();
//        String key = "getFileInputStreamById:" + id;
//        Long expire = bladeRedis.get(key);
//        if (expire != null && expire > now) {
//            return R.fail("当前文件正在使用,请稍候再试!");
//        }
//        long timeout = now + (1000 * 60 * 10);
//        bladeRedis.setEx(key, timeout, timeout);

        synchronized (id) {
            PlatomixSystemFile file = platomixSystemFileService.getById(id);
            String filePath = picDir + file.getFilePath().replace("uploads/", "");
            writeFile(resp, Files.newInputStream(new File(filePath).toPath()));
//        bladeRedis.del(key);
            return R.data(file);
        }


    }

    @PostMapping("/updateFileName")
    @ApiOperation(value = " 根据 id 修改文件")
    public R getFileById(@RequestBody PlatomixSystemFile file) {
        if (StringUtils.isBlank(file.getId() + "")) {
            return R.fail("文件 id 不能为空!");
        }
        PlatomixSystemFile one = platomixSystemFileService.getById(file.getId());
        one.setFileName(file.getFileName());
        platomixSystemFileService.updateById(one);
        return R.data(one);
    }

    @PostMapping("/uploadFile/record")
    @ApiOperation(value = "上传附件", notes = "上传附件，不大于100M")
    public R<PlatomixSystemFile> uploadFileRecord(@RequestParam(value = "serialNumber", required = false) String serialNumber,
                                                  @RequestParam(value = "fileName", required = false) String fileName,
                                                  @RequestParam(value = "fileOrgId", required = false) String fileOrgId,
                                                  @RequestParam(value = "fileOrgType", required = false) String fileOrgType,
                                                  @RequestParam(value = "tenantId", required = false) String tenantId,
                                                  MultipartFile file) throws IOException {
        if (null == file) {
            return R.fail("文件不能为空");
        }
        String oFileName = file.getOriginalFilename();
        String fileSuffix = oFileName.substring(oFileName.lastIndexOf("."));
        if (!".jpg".equalsIgnoreCase(fileSuffix) &&
                !".jpeg".equalsIgnoreCase(fileSuffix) &&
                !".gif".equalsIgnoreCase(fileSuffix) &&
                !".png".equalsIgnoreCase(fileSuffix) &&
                !".pdf".equalsIgnoreCase(fileSuffix) &&
                !".doc".equalsIgnoreCase(fileSuffix) &&
                !".docx".equalsIgnoreCase(fileSuffix) &&
                !".xls".equalsIgnoreCase(fileSuffix) &&
                !".jar".equalsIgnoreCase(fileSuffix) &&
                !".svg".equalsIgnoreCase(fileSuffix) &&
                !".xlsx".equalsIgnoreCase(fileSuffix)&&false) {

            return R.fail("只能上传jpg/jpeg/gif/png/pdf/doc/xls/jar/svg类型的文件");
        }
        if (file.getSize() > 1024 * 1000 * 500) {
            return R.fail("附件不得大于500M");
        }

        Date date = new Date();
        if (StringUtils.isBlank(tenantId)) {
            tenantId = AuthUtil.getTenantId();
        }
//        String tenantId = AuthUtil.getTenantId();
        if (StringUtils.isBlank(tenantId)) {
            tenantId = "admin";
        }
        String path = tenantId + File.separator + DateUtil.year(date) + File.separator + DateUtil.quarter(date);
        FileUtil.mkdir(path);

        String tempFileName = path + File.separator + UUID.randomUUID().toString() + fileSuffix;

        File f = new File(picDir + tempFileName);
        try {
            FileUtil.writeFromStream(file.getInputStream(), f);
        } catch (IOException e) {
            e.printStackTrace();
        }
        PlatomixSystemFile platomixSystemFile = new PlatomixSystemFile();
        platomixSystemFile.setFileExtension(fileSuffix);
        platomixSystemFile.setFileType(FileUtil.getType(f));
        platomixSystemFile.setFilePath(UPLOADS + tempFileName);
        platomixSystemFile.setFileOrgId(fileOrgId);
        platomixSystemFile.setFileOrgType(fileOrgType);
        platomixSystemFile.setFileSize(file.getSize());
        platomixSystemFile.setFileSizeStr(ByteUnitConversionUtil.formatFileSize(file.getSize()));
        platomixSystemFile.setCreateUser(AuthUtil.getUserId().toString());
        platomixSystemFile.setCreateDept(AuthUtil.getDeptId());
        platomixSystemFile.setCreateTime(date);
        platomixSystemFile.setUpdateUser(AuthUtil.getUserId().toString());
        platomixSystemFile.setUpdateTime(date);
        platomixSystemFile.setTenantId(tenantId);


        if (StringUtils.isNotBlank(fileName)) {
            platomixSystemFile.setFileName(fileName);
        } else {
            platomixSystemFile.setFileName(oFileName);
        }
        platomixSystemFileService.save(platomixSystemFile);
        if (StringUtils.isNotBlank(serialNumber)) {
            SetOperations<String, Object> setOps = bladeRedis.getSetOps();
            setOps.add(serialNumber, platomixSystemFile);
            bladeRedis.expire(serialNumber, Duration.ofMinutes(10));
        }
        return R.data(platomixSystemFile, UPLOADS + tempFileName);
    }

    @PostMapping("/getBySerialNumber")
    @ApiOperation(value = "流水号", notes = "根据流水号获取文件集合 url")
    public R getBySerialNumber(@RequestParam("serialNumber") String serialNumber) {
        if (StringUtils.isBlank(serialNumber)) {
            return R.fail("流水号不能为空");
        }
        SetOperations<String, Object> setOps = bladeRedis.getSetOps();
        Set<Object> members = setOps.members(serialNumber);
        return R.data(members);
    }

    @PostMapping("/delBySerialNumber")
    @ApiOperation(value = "流水号", notes = "根据流水号 删除文件集合 对应文件")
    public R delBySerialNumber(@RequestParam("serialNumber") String serialNumber, @RequestParam("id") String id, @RequestParam("fileUrl") String fileUrl) {
        if (StringUtils.isBlank(serialNumber)) {
            return R.fail("流水号不能为空");
        }
        SetOperations<String, Object> setOps = bladeRedis.getSetOps();
        Set<Object> members = setOps.members(serialNumber);
        if (members != null) {
            for (Object member : members) {
                if (member instanceof PlatomixSystemFile) {
                    if (((PlatomixSystemFile) member).getId().toString().equals(id)) {
                        setOps.remove(serialNumber, member);
                    } else if (StrUtil.isNotBlank(fileUrl) && ((PlatomixSystemFile) member).getId().toString().equals(fileUrl)) {
                        setOps.remove(serialNumber, member);
                    } else {
                        setOps.remove(serialNumber, fileUrl);
                    }
                }
            }
        }
//        Set<Object> members = setOps.members(serialNumber);
//        if(CollectionUtil.isNotEmpty(members)){
//            members.remove(fileUrl);
//        }
        return R.data(setOps.members(serialNumber));
    }

    @PostMapping("/uploadStaticJson")
    @ApiOperation(value = "上传静态json", notes = "上传静态json")
    public R uploadStaticJson(@RequestBody String json) {
        if (StringUtils.isBlank(json)) {
            return R.fail("json不能为空");
        }
        String tempFileName = UUID.randomUUID().toString() + ".json";

        File f = new File(picDir + tempFileName);
        try {
            String decoderStr = new String(Base64.getDecoder().decode(json), "utf-8");
            FileUtil.writeUtf8String(decoderStr, f);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return R.success(UPLOADS + tempFileName);
    }

    /**
     * 将输入流输出到页面
     *
     * @param resp
     * @param inputStream
     * @date: 2020年11月17日
     */
    private void writeFile(HttpServletResponse resp, InputStream inputStream) throws Exception {
        OutputStream out = null;
        try {
            out = resp.getOutputStream();
            int len = 0;
            byte[] b = new byte[1024];
            while ((len = inputStream.read(b)) != -1) {
                out.write(b, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
