package com.jwipc.sys.controller.pc;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.jwipc.sys.dto.FileResposeDTO;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.util.FileNameUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.jwipc.sys.constant.ModuleConst.MODULE_ROOT;

/**
 * <p> </p>
 *
 * @author ZhangJie
 * @version 1.0
 * @since JDK 1.8
 */
@RestController
@RequestMapping(MODULE_ROOT + "/file/rest/")
@RequiredArgsConstructor
@CrossOrigin(origins = "*")
public class FileRestController {
    private final FileLogic fileLogic;

    @PostMapping("upload/file")
    public ResponseEntity uploadFile(@RequestPart("file") MultipartFile file) {
        FileResposeDTO respoDTO = fileLogic.uploadFile(file);
        return ResponseEntity.ok(respoDTO);
    }

    /**
     * ue编辑器上传接口
     */
    @RequestMapping("ue/upload/file")
    public Object ueUploadFile(String action, @RequestParam(required = false) MultipartFile upfile) {
        if (StringUtils.equals(action, "config")) {
            String json = ResourceUtil.readUtf8Str("json/UEconfig.json");
            return JSON.parse(json);
        }
        FileResposeDTO respoDTO = fileLogic.uploadFile(upfile);
        Map<String, Object> imgInfo = Maps.newHashMap();
        imgInfo.put("url", "/pc/sys/file/rest/download/" + respoDTO.getId());
        imgInfo.put("name", respoDTO.getFileName());
        imgInfo.put("type", respoDTO.getFileType());
        imgInfo.put("original", respoDTO.getFileName());
        imgInfo.put("title", respoDTO.getFileName());
        imgInfo.put("state", "SUCCESS");
        imgInfo.put("size", respoDTO.getFileSize());
        return imgInfo;
    }

    /**
     * layui编辑器上传图片接口
     */
    @RequestMapping("layui/upload/image")
    public Object uploadImage(String action, @RequestParam("file") MultipartFile[] files) {
        List<FileResposeDTO> respoDTOs = fileLogic.uploadFiles(files);
        List<String> url = new ArrayList<>();
        respoDTOs.forEach(fileResposeDTO -> {
            url.add("/pc/sys/file/rest/download/" + fileResposeDTO.getId());
        });
        Map<String, Object> imgInfo = Maps.newHashMap();
        imgInfo.put("data", url);
        imgInfo.put("errno", 0);
        return imgInfo;
    }

    @PostMapping("upload/files")
    public ResponseEntity uploadFiles(@RequestPart("files") MultipartFile[] files) {
        List<FileResposeDTO> respoDTOs = fileLogic.uploadFiles(files);
        return ResponseEntity.ok(respoDTOs);
    }

    @GetMapping("/download/{id}")
    public ResponseEntity<byte[]> downloadFile(@PathVariable("id") Long fileId,
                                               HttpServletResponse response)
    {
        FileResposeDTO fileResposeDTO = fileLogic.getForDownload1(fileId);

        if (fileResposeDTO == null) {
            return ResponseEntity.notFound().build();
        }

        String fileName = fileResposeDTO.getFileName();
        String filePath = fileResposeDTO.getFilePath();
        if(!FileUtil.exist(filePath)){
            return ResponseEntity.notFound().build();
        }
        String encodedFileName = FileNameUtil.replace(fileName);

        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        // 下载文件能正常显示中文
        response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
        // 实现文件下载
        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(filePath);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ResponseEntity.ok().build();
    }

    @GetMapping("/downloadBatch")
    public void downloadBatch(@RequestParam("ids") String ids, HttpServletResponse response) throws IOException {

        // 解析 ids
        List<Long> fileIds = Arrays.stream(ids.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(Long::valueOf)
                .distinct()
                .collect(Collectors.toList());

        if (fileIds.isEmpty()) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        String zipName = "attachments_" + System.currentTimeMillis() + ".zip";
        // 如果你们 FileNameUtil.replace 是做中文兼容的，可以继续用
        String encodedZipName = FileNameUtil.replace(zipName);

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + encodedZipName);

        // 关键：zip 流输出
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            byte[] buffer = new byte[8192];

            for (Long fileId : fileIds) {
                FileResposeDTO dto = fileLogic.getForDownload1(fileId);
                if (dto == null) continue;

                String fileName = dto.getFileName();
                String filePath = dto.getFilePath();
                if (!FileUtil.exist(filePath)) continue;

                // zip 内部文件名，建议做一下去重/防止重名覆盖
                String entryName = safeZipEntryName(fileName);

                zos.putNextEntry(new ZipEntry(entryName));

                try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) {
                    int len;
                    while ((len = bis.read(buffer)) != -1) {
                        zos.write(buffer, 0, len);
                    }
                } catch (Exception ex) {
                    // 单个文件失败：关闭 entry 继续下一个（不要让整个 zip 下载失败）
                } finally {
                    zos.closeEntry();
                }
            }
            zos.finish();
        }
    }

    // 防止 zip entry 名非法、路径穿越、空文件名等
    private String safeZipEntryName(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            return "unknown_" + System.currentTimeMillis();
        }
        // 防止 ../ 之类的路径穿越
        fileName = fileName.replace("\\", "/");
        fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
        return fileName;
    }


    @GetMapping("getFileListByFileIds")
    public ResponseEntity<List<FileResposeDTO>> getFileListByFileIds(String fileIds) {
        return ResponseEntity.ok(fileLogic.getFileListByFileIds(fileIds));
    }

    /**
     * 删除文件
     * @param fileIds 文件ID列表
     * @return 无
     */
    @GetMapping("delete/file")
    public ResponseEntity<Boolean> deleteFile(@RequestParam String fileIds) {
        List<Long> fileIdList = Arrays.stream(fileIds.split(","))
                .map(String::trim)
                .filter(id -> !id.isEmpty())
                .map(Long::valueOf)
                .collect(Collectors.toList());
        fileLogic.deleteFile(fileIdList);
        return ResponseEntity.ok().build();
    }
}
