package org.qinan.safetyeval.app.executor;

import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.qinan.safetyeval.client.api.FileUploadApi;
import org.qinan.safetyeval.client.co.FileInfoCO;
import org.qinan.safetyeval.client.dto.SingleResponse;
import org.qinan.safetyeval.domain.entity.FileStorage;
import org.qinan.safetyeval.domain.exception.BizException;
import org.qinan.safetyeval.domain.exception.ErrorCode;
import org.qinan.safetyeval.domain.service.FileStorageDomainService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件上传执行器（App层）
 * <p>
 * 负责文件上传至阿里云 OSS，并在上传完成后将元信息同步写入 filestorage 表。
 * 区分公开上传（创建人=system）与内部上传（创建人=当前登录用户）。
 * </p>
 *
 * @author safety-eval
 */
@Service
public class FileUploadExecutor implements FileUploadApi {

    private static final Logger log = LoggerFactory.getLogger(FileUploadExecutor.class);

    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private FileStorageDomainService fileStorageDomainService;

    // ==================== 公开上传（创建人默认 system） ====================

    @Override
    public SingleResponse<FileInfoCO> uploadPublic(MultipartFile file) {
        return doUpload(file, false);
    }

    @Override
    public SingleResponse<List<FileInfoCO>> uploadPublicBatch(List<MultipartFile> files) {
        return doUploadBatch(files, false);
    }

    // ==================== 内部上传（创建人为当前用户） ====================

    @Override
    public SingleResponse<FileInfoCO> uploadInternal(MultipartFile file) {
        return doUpload(file, true);
    }

    @Override
    public SingleResponse<List<FileInfoCO>> uploadInternalBatch(List<MultipartFile> files) {
        return doUploadBatch(files, true);
    }

    // ==================== 私有方法 ====================

    /**
     * 执行单个文件上传并同步写入 filestorage 表
     *
     * @param file       上传的文件
     * @param isInternal true-内部（取当前用户），false-公开（creator=system）
     */
    private SingleResponse<FileInfoCO> doUpload(MultipartFile file, boolean isInternal) {
        if (file == null || file.isEmpty()) {
            throw new BizException(ErrorCode.FILE_UPLOAD_EMPTY);
        }
        try {
            // 1. 上传到 OSS
            FileInfo ossFileInfo = fileStorageService.of(file).upload();
            log.info("OSS upload success: url={}, size={}, isInternal={}",
                    ossFileInfo.getUrl(), ossFileInfo.getSize(), isInternal);

            // 2. 同步元信息到本地 filestorage 表
            FileStorage fileStorage = FileStorageHelper.buildResource(ossFileInfo, file.getOriginalFilename(), isInternal);
            FileStorage saved = fileStorageDomainService.saveResource(fileStorage);

            return SingleResponse.success(FileStorageHelper.toCO(saved, null));
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("File upload failed: {}, isInternal={}", file.getOriginalFilename(), isInternal, e);
            throw new BizException(ErrorCode.FILE_UPLOAD_FAILED, e);
        }
    }

    /**
     * 批量上传
     */
    private SingleResponse<List<FileInfoCO>> doUploadBatch(List<MultipartFile> files, boolean isInternal) {
        if (files == null || files.isEmpty()) {
            throw new BizException(ErrorCode.FILE_UPLOAD_EMPTY);
        }
        List<FileInfoCO> results = new ArrayList<>();
        for (MultipartFile file : files) {
            if (file == null || file.isEmpty()) {
                continue;
            }
            SingleResponse<FileInfoCO> result = doUpload(file, isInternal);
            if (result.isSuccess() && result.getData() != null) {
                results.add(result.getData());
            }
        }
        return SingleResponse.success(results);
    }
}
