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

import cn.reghao.tnb.oss.api.dto.ObjectChannel;
import cn.reghao.tnb.oss.store.service.*;
import cn.reghao.tnb.oss.store.util.AuthContext;
import cn.reghao.tnb.oss.api.rest.UploadFileRet;
import cn.reghao.tnb.oss.store.model.vo.ObjectProp;
import cn.reghao.tnb.oss.store.model.vo.ObjectResult;
import cn.reghao.tnb.auth.JwtUtil;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.jutil.jdk.web.result.WebResult;
import cn.reghao.jutil.jdk.security.DigestUtil;
import cn.reghao.tnb.common.web.ServletUtil;
import cn.reghao.tnb.auth.model.OssPayload;
import com.github.benmanes.caffeine.cache.Cache;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.UUID;

/**
 * 对象上传接口
 *
 * @author reghao
 * @date 2023-05-19 16:20:12
 */
@RestController
public class ObjectUploadController {
    private final ChannelValidateService channelValidateService;
    private final FileStoreService fileStoreService;
    private final ObjectNameService objectNameService;
    private final PutObjectService putObjectService;
    private final ConsoleServiceWrapper consoleServiceWrapper;
    private final Cache<String, String> cache;

    public ObjectUploadController(ChannelValidateService channelValidateService, FileStoreService fileStoreService,
                                  ObjectNameService objectNameService, PutObjectService putObjectService,
                                  ConsoleServiceWrapper consoleServiceWrapper, Cache<String, String> cache) {
        this.channelValidateService = channelValidateService;
        this.fileStoreService = fileStoreService;
        this.objectNameService = objectNameService;
        this.putObjectService = putObjectService;
        this.consoleServiceWrapper = consoleServiceWrapper;
        this.cache = cache;
    }

    // 使用 PUT 方法上传对象
    @PutMapping(value = "/**")
    public String putObject(@RequestBody File file) {
        return WebResult.failWithMsg("not implement");
    }

    // 使用 POST 方法上传对象
    @PostMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> postObject(MultipartFile file, Integer channelCode, String objectName,
                                             String client, String sha256sum) throws Exception {
        /* 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);

        /* channel validate */
        String contentId = UUID.randomUUID().toString().replace("-", "");
        long size = file.getSize();
        File savedFile = fileStoreService.saveFile(file.getInputStream(), contentId, size);
        Result result = channelValidateService.validateFile(savedFile, objectChannel);
        if (result.getCode() != 0) {
            FileUtils.deleteQuietly(savedFile);
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(WebResult.result(result));
        }

        /* store file */
        String sha256sum1 = sha256sum;
        if (sha256sum1 == null) {
            sha256sum1 = DigestUtil.sha256sum(savedFile.getAbsolutePath());
        }

        String filename = file.getOriginalFilename();
        if (filename == null) {
            filename = "";
        }

        ObjectProp objectProp = objectNameService.getObjectProp(objectChannel, filename);
        ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, filename, sha256sum1);
        String objectId = objectResult.getObjectId();
        String domain = ServletUtil.getHeader("host");
        String objectUrl = String.format("//%s/%s", domain, objectResult.getObjectName());
        UploadFileRet uploadFileRet;
        if (objectChannel.isSetUrl()) {
            uploadFileRet = new UploadFileRet(objectId, objectUrl);
        } else {
            uploadFileRet = new UploadFileRet(objectId);
        }

        return ResponseEntity.status(HttpStatus.OK).body(WebResult.success(uploadFileRet));
    }

    // 删除对象
    @DeleteMapping(value = "/")
    public ResponseEntity<String> deleteObject(String objectId) {
        //putObjectService.deleteObject(objectId);
        return ResponseEntity.ok().build();
    }
}
