package cn.reghao.tnb.oss.store.controller;

import cn.reghao.tnb.common.web.ServletUtil;
import cn.reghao.tnb.oss.api.dto.ObjectChannel;
import cn.reghao.tnb.auth.model.OssPayload;
import cn.reghao.tnb.oss.store.util.AuthContext;
import cn.reghao.tnb.auth.JwtUtil;
import cn.reghao.tnb.oss.api.rest.UploadFilePart;
import cn.reghao.tnb.oss.api.rest.UploadFileRet;
import cn.reghao.tnb.oss.api.rest.UploadedPart;
import cn.reghao.tnb.oss.store.service.ConsoleServiceWrapper;
import cn.reghao.tnb.oss.store.service.ObjectMultipartUploadService;
import cn.reghao.jutil.jdk.web.result.WebResult;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * 分片上传接口
 *
 * @author reghao
 * @date 2022-12-08 20:40:55
 */
@RestController
public class ObjectMultipartUploadController {
    private final ObjectMultipartUploadService objectMultipartUploadService;
    private final ConsoleServiceWrapper consoleServiceWrapper;
    private final Cache<String, String> cache;

    public ObjectMultipartUploadController(ObjectMultipartUploadService objectMultipartUploadService,
                                           ConsoleServiceWrapper consoleServiceWrapper, Cache<String, String> cache) {
        this.objectMultipartUploadService = objectMultipartUploadService;
        this.consoleServiceWrapper = consoleServiceWrapper;
        this.cache = cache;
    }

    // 获取已上传的对象分片
    @GetMapping(value = "/", params = {"multiparts"}, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> getUploadedPart(UploadFilePart uploadFilePart) throws Exception {
        int channelCode = uploadFilePart.getChannelCode();
        /* permission check */
        String token = ServletUtil.getBearerToken();
        if (token == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(WebResult.failWithMsg("no token in request"));
        }

        String secretKey = cache.getIfPresent(token);
        OssPayload ossPayload = JwtUtil.getOssPayload(token, secretKey);
        String action = ossPayload.getAction();
        if (!"upload".equals(action)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg("it's not upload token"));
        }

        int channelCode1 = ossPayload.getChannelCode();
        if (channelCode != channelCode1) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg("channel not match in token"));
        }

        int loginUser = ossPayload.getUserId();
        ObjectChannel objectChannel = consoleServiceWrapper.getChannelByCode(loginUser, channelCode);
        if (objectChannel == null) {
            String errMsg = String.format("channel validate failed, channel %s not exist", channelCode);
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg(errMsg));
        }
        AuthContext context = new AuthContext(loginUser);

        UploadedPart uploadedPart = objectMultipartUploadService.getUploadedPart(uploadFilePart, objectChannel);
        return ResponseEntity.status(HttpStatus.OK).body(WebResult.success(uploadedPart));
    }

    // 上传对象分片
    @PostMapping(value = "/", params = {"multiparts"}, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> uploadPart(MultipartFile file, @Validated UploadFilePart uploadFilePart) throws Exception {
        int channelCode = uploadFilePart.getChannelCode();
        /* permission check */
        String token = ServletUtil.getBearerToken();
        if (token == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(WebResult.failWithMsg("no token in request"));
        }

        String secretKey = cache.getIfPresent(token);
        OssPayload ossPayload = JwtUtil.getOssPayload(token, secretKey);
        String action = ossPayload.getAction();
        if (!"upload".equals(action)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg("it's not upload token"));
        }

        int channelCode1 = ossPayload.getChannelCode();
        if (channelCode != channelCode1) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg("channel not match in token"));
        }

        int loginUser = ossPayload.getUserId();
        ObjectChannel objectChannel = consoleServiceWrapper.getChannelByCode(loginUser, channelCode);
        if (objectChannel == null) {
            String errMsg = String.format("channel validate failed, channel %s not exist", channelCode);
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(WebResult.failWithMsg(errMsg));
        }
        AuthContext context = new AuthContext(loginUser);

        UploadFileRet uploadFileRet = objectMultipartUploadService.putFilePart(file.getInputStream(), uploadFilePart, objectChannel);
        return ResponseEntity.status(HttpStatus.OK).body(WebResult.success(uploadFileRet));
    }
}
