package com.datamate.common.domain.service;

import com.datamate.common.domain.model.ChunkUploadPreRequest;
import com.datamate.common.domain.model.ChunkUploadRequest;
import com.datamate.common.domain.model.FileUploadResult;
import com.datamate.common.domain.utils.ChunksSaver;
import com.datamate.common.infrastructure.exception.BusinessException;
import com.datamate.common.infrastructure.exception.CommonErrorCode;
import com.datamate.common.infrastructure.mapper.ChunkUploadRequestMapper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
 * 文件服务
 */
@Component
public class FileService {
    private static final int DEFAULT_TIMEOUT = 1800;

    private final ChunkUploadRequestMapper chunkUploadRequestMapper;

    public FileService(ChunkUploadRequestMapper chunkUploadRequestMapper) {
        this.chunkUploadRequestMapper = chunkUploadRequestMapper;
    }

    /**
     * 预上传
     */
    @Transactional
    public String preUpload(ChunkUploadPreRequest chunkUploadPreRequest) {
        chunkUploadPreRequest.setId(UUID.randomUUID().toString());
        chunkUploadPreRequest.setTimeout(LocalDateTime.now().plusSeconds(DEFAULT_TIMEOUT));
        chunkUploadRequestMapper.insert(chunkUploadPreRequest);
        return chunkUploadPreRequest.getId();
    }

    /**
     * 切片上传
     */
    @Transactional
    public FileUploadResult chunkUpload(ChunkUploadRequest uploadFileRequest) {
        uploadFileRequest.setFileSize(uploadFileRequest.getFile().getSize());
        ChunkUploadPreRequest preRequest = chunkUploadRequestMapper.findById(uploadFileRequest.getReqId());
        if (preRequest == null || preRequest.isUploadComplete() || preRequest.isRequestTimeout()) {
            throw BusinessException.of(CommonErrorCode.PRE_UPLOAD_REQUEST_NOT_EXIST);
        }
        File savedFile;
        if (uploadFileRequest.getTotalChunkNum() > 1) {
            savedFile = uploadChunk(uploadFileRequest, preRequest);
        } else {
            savedFile = uploadFile(uploadFileRequest, preRequest);
        }
        if (chunkUploadRequestMapper.update(preRequest) == 0) {
            throw BusinessException.of(CommonErrorCode.PRE_UPLOAD_REQUEST_NOT_EXIST);
        }
        boolean isFinish = Objects.equals(preRequest.getUploadedFileNum(), preRequest.getTotalFileNum());
        if (isFinish) {
            // 删除存分片的临时路径
            ChunksSaver.deleteFolder(new File(preRequest.getUploadPath(),
                String.format(ChunksSaver.TEMP_DIR_NAME_FORMAT, preRequest.getId())).getPath());
            chunkUploadRequestMapper.deleteById(preRequest.getId());
        }
        return FileUploadResult.builder()
            .isAllFilesUploaded(isFinish)
            .checkInfo(preRequest.getCheckInfo())
            .savedFile(savedFile)
            .fileName(uploadFileRequest.getFileName())
            .build();
    }

    /**
     * 取消上传
     */
    @Transactional
    public void cancelUpload(String reqId) {
        if (reqId == null || reqId.isBlank()) {
            throw BusinessException.of(CommonErrorCode.PARAM_ERROR);
        }
        ChunkUploadPreRequest preRequest = chunkUploadRequestMapper.findById(reqId);
        if (preRequest == null) {
            return;
        }
        String uploadPath = preRequest.getUploadPath();
        if (uploadPath != null && !uploadPath.isBlank()) {
            File tempDir = new File(uploadPath, String.format(ChunksSaver.TEMP_DIR_NAME_FORMAT, preRequest.getId()));
            ChunksSaver.deleteFolder(tempDir.getPath());
        }
        chunkUploadRequestMapper.deleteById(reqId);
    }

    private File uploadFile(ChunkUploadRequest fileUploadRequest, ChunkUploadPreRequest preRequest) {
        File savedFile = ChunksSaver.saveFile(fileUploadRequest, preRequest);
        preRequest.setTimeout(LocalDateTime.now().plusSeconds(DEFAULT_TIMEOUT));
        preRequest.incrementUploadedFileNum();
        return savedFile;
    }

    private File uploadChunk(ChunkUploadRequest fileUploadRequest, ChunkUploadPreRequest preRequest) {
        Optional<File> savedFile = ChunksSaver.save(fileUploadRequest, preRequest);
        if (savedFile.isPresent()) {
            preRequest.incrementUploadedFileNum();
            return savedFile.get();
        }
        preRequest.setTimeout(LocalDateTime.now().plusSeconds(DEFAULT_TIMEOUT));
        return null;
    }
}
