package cc.smtweb.system.bpm.spring.controller;

import cc.smtweb.framework.core.cache.redis.RedisManager;
import cc.smtweb.framework.core.session.SessionUtil;
import cc.smtweb.system.bpm.util.FilePathGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.concurrent.TimeUnit;

@RestController
public class FileDownloadController {
    private static final MediaType APPLICATION_JAVASCRIPT = new MediaType("application", "javascript");
    @Value("${smtweb.static.local-path:}")
    private String staticLocalPath;

    @Autowired
    private FilePathGenerator filePathGenerator;

    /**
     * path方式下载文件
     */
    @GetMapping("/fs/files/**")
    public ResponseEntity<InputStreamResource> files(@RequestParam(value = "name", required = false) String name,
                                                     @RequestParam(value = "noCache", required = false) Boolean noCache,
                                                     @RequestParam(value = "absolutePath", required = false) Boolean absolutePath,
                                                     HttpServletRequest request
    ) throws FileNotFoundException {
        String filePath = request.getServletPath().substring(10);
        return download(filePath, name, noCache,absolutePath, request);
    }

    /**
     * 参数方式下载文件
     */
    @GetMapping("/fs/download")
    public ResponseEntity<InputStreamResource> download(@RequestParam(value = "path") String path,
                                                        @RequestParam(value = "name", required = false) String name,
                                                        @RequestParam(value = "noCache", required = false) Boolean noCache,
                                                        @RequestParam(value = "absolutePath", required = false) Boolean absolutePath,
                                                        HttpServletRequest request
    ) throws FileNotFoundException {
        File file = new File(absolutePath? path:filePathGenerator.getFileDiskPath(path));

        if (!file.exists()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }

        if (StringUtils.isBlank(name)) {
            name = file.getName();
        }

        HttpHeaders headers = new HttpHeaders();
        if (Boolean.TRUE.equals(noCache)) {
            headers.setCacheControl("no-cache, no-store, must-revalidate");
            headers.setPragma("no-cache");
            headers.setExpires(0);
        }

        headers.setLastModified(file.lastModified());
        headers.add("Content-Disposition",
                String.format("attachment; filename=\"%s\"", new String(name.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)));

        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(new InputStreamResource(new FileInputStream(file)));
    }

    /**
     * path方式读取静态目录文件
     */
    @GetMapping("/fs/static/**")
    public ResponseEntity<InputStreamResource> resource(@RequestParam(value = "default", required = false) String defaultPath,
                                                        @RequestParam(value = "noCache", required = false) Boolean noCache,
                                                        @RequestHeader(value = "If-Modified-Since", required = false) String ifModifiedSince,
                                                        HttpServletRequest request) throws FileNotFoundException {
        String filePath = request.getServletPath().substring(11);

        HttpHeaders headers = new HttpHeaders();

        if (Boolean.TRUE.equals(noCache)) {
            headers.setCacheControl("no-cache, no-store, must-revalidate");
            headers.setPragma("no-cache");
            headers.setExpires(0);
        } else {
            // 暂时缓存1天
            headers.setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS));
            headers.setExpires(Instant.ofEpochMilli(System.currentTimeMillis() + DateUtils.MILLIS_PER_DAY));
        }

        String name = getFileName(filePath);
        headers.add("Content-Disposition",
                String.format("attachment; filename=\"%s\"", new String(name.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)));

        MediaType contentType = getContentType(filePath);
        // 先找文件
        if (StringUtils.isNotBlank(staticLocalPath)) {
            File file = new File(staticLocalPath + filePath);

            if (file.exists()) {
                headers.setLastModified(file.lastModified());

                return ResponseEntity.ok()
                        .headers(headers)
                        .contentLength(file.length())
                        .contentType(contentType)
                        .body(new InputStreamResource(new FileInputStream(file)));
            }
        }

        // 再找资源目录
        InputStream inputStream = getClass().getResourceAsStream("/static/" + filePath);
        if (inputStream != null) {
            return buildResource(inputStream, contentType, headers);
        } else if (StringUtils.isNotBlank(defaultPath)) {
            inputStream = getClass().getResourceAsStream("/static/" + defaultPath);
            if (inputStream != null) {
                return buildResource(inputStream, contentType, headers);
            }
        }

        return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    }

    private String getFileName(String filePath) {
        int pos = filePath.lastIndexOf("/");
        if (pos >= 0) {
            return filePath.substring(pos + 1);
        }

        return filePath;
    }

    private ResponseEntity<InputStreamResource> buildResource(InputStream inputStream, MediaType contentType, HttpHeaders headers) {
        return ResponseEntity.ok()
                .headers(headers)
//              .contentLength(file.length())
                .contentType(contentType)
                .body(new InputStreamResource(inputStream));
    }

    private static MediaType getContentType(String filePath) {
        int pos = filePath.lastIndexOf(".");

        if (pos >= 0) {
            String fileExt = filePath.substring(pos + 1).toLowerCase();
            switch (fileExt) {
                case "htm":
                case "html":
                case "css":
                    return MediaType.TEXT_HTML;
                case "js":
                    return APPLICATION_JAVASCRIPT;
                case "txt":
                    return MediaType.TEXT_PLAIN;
                case "pdf":
                    return MediaType.APPLICATION_PDF;
                case "xml":
                    return MediaType.TEXT_XML;
                case "gif":
                    return MediaType.IMAGE_GIF;
                case "jpeg":
                case "jpg":
                    return MediaType.IMAGE_JPEG;
                case "png":
                    return MediaType.IMAGE_PNG;
                default:
                    return MediaType.APPLICATION_OCTET_STREAM;
            }
        }

        return MediaType.APPLICATION_OCTET_STREAM;
    }
}
