package com.micer.easyball.controller;

import com.micer.easyball.ApiVersion;

import com.micer.easyball.pojo.ResponseResult;
import com.micer.easyball.pojo.LoginUser;
import com.micer.easyball.service.FileAccessService;
import com.micer.easyball.utils.JwtUtil;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.parameters.P;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;

@RestController
@RequestMapping(ApiVersion.V1)
public class FileController {
    @org.springframework.beans.factory.annotation.Autowired
    private FileAccessService fileAccessService;
    private static final Set<String> ALLOWED_EXTENSIONS = 
            new HashSet<>(Arrays.asList("jpg", "jpeg", "png"));
    /**
     * 上传文件（只接受.jpg, .png, .jpeg）
     * @param file 文件
     * @param gameId 比赛ID
     * @return 返回文件相对路径
     */
    @PostMapping("/file/upload")
    @PreAuthorize("@ex.hasRole('ROLE_CLUB_ADMIN')")
    @Transactional
    public ResponseResult upload(@RequestParam MultipartFile file,
                                 @RequestParam String gameId)
            throws IOException
    {

        if (Objects.isNull(file))
        {
            return new ResponseResult(511, "文件不存在");
        }
        // 获取文件后缀并校验白名单
        String originalFilename = file.getOriginalFilename();
        String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();

        if (!ALLOWED_EXTENSIONS.contains(ext)) {
            return new ResponseResult(512, "仅支持 jpg、jpeg、png 格式");
        }

        // 对比赛归属进行服务端校验
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getId();

        if (!fileAccessService.canAccessGame(userId, gameId)) {
            return new ResponseResult(403, "无权操作该比赛");
        }

        // 重命名文件
        String uuid = JwtUtil.getUUID();
        String fileName = uuid + "." + ext;

        // 获取新路径
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        String pre = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() + File.separator + "image" + File.separator + gameId + File.separator;
        String path = pre + fileName;

        // 创建文件夹
        File folder = new File(pre);
        if (!folder.exists())
        {
            folder.mkdirs();
        }

        // 转存到指定位置
        try {
            file.transferTo(new File(path));
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        return new ResponseResult(200, "上传成功", File.separator + "image" + File.separator + gameId + File.separator + fileName);
    }

    /**
     * 下载文件
     * @param fileName 文件相对路径
     * @param response
     */
    @GetMapping("/file/download")
    @PreAuthorize("@ex.hasRole('ROLE_CLUB_PLAYER')")
    @Transactional
    public void download(@RequestParam String fileName,
                         HttpServletResponse response)
            throws IOException
    {
        // 对象级权限校验
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getId();

        if (!fileAccessService.canAccessFile(userId, fileName)) {
            response.setStatus(403);
            response.getWriter().write("无权访问该文件");
            return;
        }

        // 设置文件格式
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        if ("png".equals(ext)) {
            response.setContentType("image/png");
        } else {
            response.setContentType("image/jpeg");
        }
        // 输入流，通过输入流读取文件内容
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        String pre = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath();
        FileInputStream fileInputStream = new FileInputStream(new File(pre + fileName));

        // response输出流，将文件写回浏览器
        ServletOutputStream outputStream = response.getOutputStream();

        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
            outputStream.flush();
        }

        // 关闭流
        outputStream.close();
        fileInputStream.close();
    }

    /**
     * 删除单张比赛照片
     * @param fileName 文件相对路径
     */

    @DeleteMapping("/file/deleteGameImage")
    @PreAuthorize("@ex.hasRole('ROLE_CLUB_ADMIN')")
    @Transactional
    public ResponseResult deleteGameImage(@RequestParam String fileName)
    {
        // 权限校验
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getId();

        if (!fileAccessService.canAccessFile(userId, fileName)) {
            return new ResponseResult(403, "无权删除该文件");
        }

        // 获取新路径
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        String dirPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath();

        // 删除文件
        File file = new File(dirPath + fileName);
        if (file.delete())
        {
            System.out.printf("删除成功 : %s%n", file);
            return new ResponseResult(200, "删除成功");
        } else
        {
            System.err.printf("删除失败 : %s%n", file);
            return new ResponseResult(513, "删除失败");
        }
    }

    /**
     * 删除所有比赛照片
     * @param gameId 比赛ID
     */
    @DeleteMapping("/file/deleteGameImages")
    @PreAuthorize("@ex.hasRole('ROLE_CLUB_ADMIN')")
    @Transactional
    public ResponseResult deleteGameImages(@RequestParam String gameId)
    {
        // 校验当前用户是否有权操作该比赛
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String userId = loginUser.getUser().getId();

        if (!fileAccessService.canAccessGame(userId, gameId)) {
            return new ResponseResult(403, "无权操作该比赛");
        }

        // 获取新路径
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        String dirPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() + File.separator + "image" + File.separator + gameId + File.separator;

        // 删除文件
        File file = new File(dirPath);
        deleteDirectoryLegacyIO(file);
        return new ResponseResult(200, "删除成功");
    }

    private void deleteDirectoryLegacyIO(File file) {

        File[] list = file.listFiles();  //无法做到list多层文件夹数据
        if (list != null) {
            for (File temp : list) {     //先去递归删除子文件夹及子文件
                deleteDirectoryLegacyIO(temp);   //注意这里是递归调用
            }
        }

        if (file.delete()) {     //再删除自己本身的文件夹
            System.out.printf("删除成功 : %s%n", file);
        } else {
            System.err.printf("删除失败 : %s%n", file);
        }
    }

}
