package cn.reghao.oss.store.controller;

import cn.reghao.oss.store.config.OssProperties;
import cn.reghao.oss.store.model.vo.ObjectProp;
import cn.reghao.oss.store.model.vo.ObjectResult;
import cn.reghao.oss.store.service.ChannelValidateService;
import cn.reghao.oss.store.service.FileStoreService;
import cn.reghao.oss.store.service.ObjectNameService;
import cn.reghao.oss.store.service.PutObjectService;
import cn.reghao.oss.store.task.FileProcessor;
import cn.reghao.oss.store.util.JwtUtil;
import cn.reghao.jutil.jdk.result.Result;
import cn.reghao.jutil.jdk.result.WebResult;
import cn.reghao.jutil.jdk.security.DigestUtil;
import cn.reghao.jutil.web.ServletUtil;
import cn.reghao.oss.api.dto.OssPayload;
import cn.reghao.oss.api.rest.UploadFileRet;
import cn.reghao.oss.store.util.UserContext;
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 FileProcessor fileProcessor;
    private final OssProperties ossProperties;

    public ObjectUploadController(ChannelValidateService channelValidateService, FileStoreService fileStoreService,
                                  ObjectNameService objectNameService, PutObjectService putObjectService,
                                  FileProcessor fileProcessor, OssProperties ossProperties) {
        this.channelValidateService = channelValidateService;
        this.fileStoreService = fileStoreService;
        this.objectNameService = objectNameService;
        this.putObjectService = putObjectService;
        this.fileProcessor = fileProcessor;
        this.ossProperties = ossProperties;
    }

    @PutMapping(value = "/**")
    public String putObject(@RequestBody File file) {
        return WebResult.failWithMsg("not implement");
    }

    @PostMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> postObject(MultipartFile file, Integer channelId,
                                             String client, String sha256sum, Long userId) throws Exception {
        /* permission check */
        if (client == null) {
            String token = ServletUtil.getBearerToken();
            if (token == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                        .body(WebResult.failWithMsg("no token in request"));
            }

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

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

            long userId1 = ossPayload.getUserId();
            UserContext context = new UserContext(userId1);
        } else {
            UserContext context = new UserContext(userId);
        }

        /* channel validate */
        String contentId = UUID.randomUUID().toString().replace("-", "");
        long size = file.getSize();
        File savedFile = fileStoreService.saveFile(file.getInputStream(), contentId, size);
        Result result = channelValidateService.validate(savedFile, channelId);
        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(channelId, filename);
        ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, filename, sha256sum1);
        UploadFileRet uploadFileRet;
        String errMsg;
        try {
            uploadFileRet = fileProcessor.process(objectResult, channelId);
            return ResponseEntity.status(HttpStatus.OK).body(WebResult.success(uploadFileRet));
        } catch (Exception e) {
            e.printStackTrace();
            errMsg = e.getMessage();
        }

        putObjectService.deleteObject(objectResult.getObjectId());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errMsg);
    }

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