package com.tashow.cloud.infra.controller.admin.file;

import static com.tashow.cloud.common.pojo.CommonResult.success;
import static com.tashow.cloud.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.tashow.cloud.common.pojo.CommonResult;
import com.tashow.cloud.common.pojo.PageResult;
import com.tashow.cloud.common.util.object.BeanUtils;
import com.tashow.cloud.infra.controller.admin.file.vo.file.*;
import com.tashow.cloud.infra.dal.dataobject.file.FileDO;
import com.tashow.cloud.infra.service.file.FileService;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/** 管理后台 - 文件存储 */
@RestController
@RequestMapping("/infra/file")
@Validated
@Slf4j
public class FileController {

  @Resource private FileService fileService;

  /** 上传文件", description = "模式一：后端上传文件 */
  @PostMapping("/upload")
  public CommonResult<String> uploadFile(FileUploadReqVO uploadReqVO) throws Exception {
    MultipartFile file = uploadReqVO.getFile();
    String path = uploadReqVO.getPath();
    return success(
        fileService.createFile(
            file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
  }

  /** 获取文件预签名地址", description = "模式二：前端上传文件：用于前端直接上传七牛、阿里云 OSS 等文件存储器 */
  @GetMapping("/presigned-url")
  public CommonResult<FilePresignedUrlRespVO> getFilePresignedUrl(@RequestParam("path") String path)
      throws Exception {
    return success(fileService.getFilePresignedUrl(path));
  }

  /** 创建文件", description = "模式二：前端上传文件：配合 presigned-url 接口，记录上传了上传的文件 */
  @PostMapping("/create")
  public CommonResult<Long> createFile(@Valid @RequestBody FileCreateReqVO createReqVO) {
    return success(fileService.createFile(createReqVO));
  }

  /** 删除文件 */
  @DeleteMapping("/delete")
  @PreAuthorize("@ss.hasPermission('infra:file:delete')")
  public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) throws Exception {
    fileService.deleteFile(id);
    return success(true);
  }

  /** 下载文件 */
  @GetMapping("/{configId}/get/**")
  @PermitAll
  public void getFileContent(
      HttpServletRequest request,
      HttpServletResponse response,
      @PathVariable("configId") Long configId)
      throws Exception {
    // 获取请求的路径
    String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false);
    if (StrUtil.isEmpty(path)) {
      throw new IllegalArgumentException("结尾的 path 路径必须传递");
    }
    // 解码，解决中文路径的问题 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
    path = URLUtil.decode(path);

    // 读取内容
    byte[] content = fileService.getFileContent(configId, path);
    if (content == null) {
      log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
      response.setStatus(HttpStatus.NOT_FOUND.value());
      return;
    }
    writeAttachment(response, path, content);
  }

  /** 获得文件分页 */
  @GetMapping("/page")
  @PreAuthorize("@ss.hasPermission('infra:file:query')")
  public CommonResult<PageResult<FileRespVO>> getFilePage(@Valid FilePageReqVO pageVO) {
    PageResult<FileDO> pageResult = fileService.getFilePage(pageVO);
    return success(BeanUtils.toBean(pageResult, FileRespVO.class));
  }
}
