package com.microservices.file.controller;


import com.microservices.common.core.constant.Constants;
import com.microservices.common.core.domain.R;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.utils.file.FileUtils;
import com.microservices.common.core.web.controller.BaseController;
import com.microservices.common.core.web.domain.AjaxResult;
import com.microservices.common.security.annotation.InnerAuth;
import com.microservices.file.service.ISysFileInfoService;
import com.microservices.system.api.domain.SysFileInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;

/**
 * 通用请求处理
 *
 * @author microservices
 */
@RestController
@RequestMapping("/common")
@Api(tags = "文件相关接口")
public class CommonController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(CommonController.class);

    /**
     * 上传文件存储在本地的根路径
     */
    @Value("${file.path}")
    private String localFilePath;
    @Autowired
    private ISysFileInfoService sysFileInfoService;

    /**
     * 根据文件标识下载
     *
     * @param fileIdentifier 文件标识
     */
    @GetMapping("/downloadByIdentifier/{fileIdentifier}")
    @ApiOperation("根据文件标识下载文件")
    public void downloadByIdentifier(@PathVariable("fileIdentifier") String fileIdentifier, HttpServletResponse response, HttpServletRequest request) {
        sysFileInfoService.fileDownloadByIdentifier(fileIdentifier, response, request);
    }

    /**
     * 根据文件标识获取文件实体
     *
     * @param fileIdentifier 文件标识
     */
    @GetMapping("/getFileEntityByIdentifier/{fileIdentifier}")
    @InnerAuth
    public void getFileEntityByIdentifier(@PathVariable("fileIdentifier") String fileIdentifier, HttpServletResponse response) {
        sysFileInfoService.getFileEntityByIdentifier(response, fileIdentifier);
    }

    /**
     * 打包文件
     *
     * @param packagedStructure 打包结构<文件包内路径,文件来源（文件标识或文件下载地址）>
     * @param zipFileName       压缩文件名（不包含文件后缀）
     * @param type              微服务类型
     * @param hierarchy         层次结构
     * @return 压缩包文件标识
     */
    @PostMapping(value = "/packagedFile")
    @InnerAuth
    public R<String> packagedFile(
            @RequestBody HashMap<String, String> packagedStructure
            , @RequestParam("zipFileName") String zipFileName
            , @RequestParam("type") String type
            , @RequestParam("hierarchy") String hierarchy) {
        return R.ok(sysFileInfoService.packagedFile(packagedStructure, zipFileName, type, hierarchy));
    }

    /**
     * 通用下载请求
     *
     * @param fileName 文件名称
     * @param delete   是否删除
     */
    @GetMapping("/download")
    @ApiIgnore
    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) {
        try {
            if (!FileUtils.checkAllowDownload(fileName)) {
                throw new Exception(StringUtils.format("文件名称({})非法，不允许下载。 ", fileName));
            }
            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
            String filePath = localFilePath + "/download/" + fileName;

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, realFileName);
            FileUtils.writeBytes(filePath, response.getOutputStream());
            if (delete) {
                /*2021-12-29 新增文件管理*/
                SysFileInfo sysFileInfo = new SysFileInfo();
                sysFileInfo.setFileObjectName(fileName);
                List<SysFileInfo> sysFileInfos = sysFileInfoService.selectSysFileInfoList(sysFileInfo);
                sysFileInfos.forEach((SysFileInfo fileInfo) -> {
                    sysFileInfoService.deleteSysFileInfoByFileObjectName(fileInfo.getFileObjectName());
                });
                /*结束*/
                FileUtils.deleteFile(filePath);
            }
        } catch (Exception e) {
            logger.error("下载文件失败", e);
        }
    }

    /**
     * 通用上传请求
     */
    @PostMapping("/upload")
    @ApiOperation("通用上传请求")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件实体", paramType = "form", dataType = "_file"),
            @ApiImplicitParam(name = "type", value = "文件类型（zone-identifier：专区下支持文件标识的附件，dms：资源库，cms：内容管理，resource：专区资源，pms：项目管理，pms-gitlink：项目管理gitlink附件，gitlink：gitlink附件）", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "hierarchy", value = "层级结构（eg: pms项目管理中{enterpriseIdentifier}/products,{enterpriseIdentifier}/projects,{enterpriseIdentifier}/docs/{projectId}）", paramType = "query", dataType = "String")
    })
    public AjaxResult uploadFile(@RequestPart("file") MultipartFile file, String type, String hierarchy) {
        SysFileInfo sysFileInfo = sysFileInfoService.upload(file, type, hierarchy);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("url", sysFileInfo.getDownloadUrl());
        if (sysFileInfo.getFileIdentifier() != null) {
            ajax.put("fileIdentifier", sysFileInfo.getFileIdentifier());
        }
        ajax.put("fileName", sysFileInfo.getFilePath());
        if (sysFileInfo.getFileId() != null) {
            ajax.put("fileId", sysFileInfo.getFileId());
        }
        ajax.put("fileOriginName", sysFileInfo.getFileOriginName());
        ajax.put("fileSuffix", sysFileInfo.getFileSuffix());
        ajax.put("fileSize", sysFileInfo.getFileSizeInfo());
        return ajax;
    }

    /**
     * 通用上传请求
     */
    @DeleteMapping("/byIdentifier/{fileIdentifier}")
    @ApiOperation("通用删除请求")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "文件类型（cms：内容管理，dms：资源库，resource：专区资源，pms：项目管理，pms-gitlink：项目管理gitlink附件）", paramType = "query", dataType = "String")
    })
    public AjaxResult deleteFile(@PathVariable("fileIdentifier") String fileIdentifier, @RequestParam("type") String type) {
        return toAjax(sysFileInfoService.deleteFile(fileIdentifier, type));
    }

    /**
     * 通过文件标识列表批量删除文件
     */
    @DeleteMapping("/byIdentifiers/{fileIdentifiers}")
    @ApiOperation(value = "通过文件标识列表批量删除文件", hidden = true)
    @InnerAuth
    public R<Boolean> deleteFileByIdentifiers(@PathVariable("fileIdentifiers") String fileIdentifiers) {
        return R.ok(sysFileInfoService.deleteFileByIdentifiers(fileIdentifiers));
    }

    /**
     * 本地资源通用下载
     */
    @GetMapping("/download/resource")
    @ApiIgnore
    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        try {
            if (!FileUtils.checkAllowDownload(resource)) {
                throw new Exception(StringUtils.format("资源文件({})非法，不允许下载。 ", resource));
            }
            // 本地资源路径
            String localPath = localFilePath;
            // 数据库资源地址
            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
            // 下载名称
            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, downloadName);
            FileUtils.writeBytes(downloadPath, response.getOutputStream());
        } catch (Exception e) {
            logger.error("下载文件失败", e);
        }
    }


    /**
     * 根据文件Id获取文件信息
     */
    @InnerAuth
    @GetMapping("/getFileByFileIdentifier/{fileIdentifier}")
    @ApiOperation(value = "根据文件Id获取文件信息")
    public R<SysFileInfo> getFileByFileIdentifier(@PathVariable("fileIdentifier") String fileIdentifier) {
        SysFileInfo sysFileInfo = sysFileInfoService.selectSysFileInfoByFileIdentifier(fileIdentifier);
        //隐藏存储路径，防止暴露文件存储细节
        sysFileInfo.setFilePath("");
        return R.ok(sysFileInfo);
    }
}
