package com.njcn.gather.aireport.testreportmulti.component;

import cn.hutool.core.util.StrUtil;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.aireport.common.constant.AiReportFileConst;
import com.njcn.gather.aireport.common.storage.AiReportMinioStorageService;
import com.njcn.gather.aireport.testreportmulti.pojo.constant.TestReportMultiConst;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
@RequiredArgsConstructor
public class TestReportMultiStorageService {

    private final AiReportMinioStorageService minioStorageService;

    public AiReportMinioStorageService.StoredFile saveSessionZip(String sessionId, MultipartFile file) {
        validateZipFile(file);
        return minioStorageService.saveMultipartFile(buildSessionZipDir(sessionId), null, file, false);
    }

    public void saveSessionExtractedFile(String sessionId, String relativePath, byte[] content, String contentType) {
        String normalizedRelativePath = normalizeRelativePath(relativePath);
        minioStorageService.saveBytes(buildSessionExtractDir(sessionId, resolveParentPath(normalizedRelativePath)),
                null, resolveFileName(normalizedRelativePath), content, contentType, true);
    }

    public byte[] readSessionExtractedBytes(String sessionId, String relativePath) {
        return minioStorageService.readBytes(buildSessionExtractObjectName(sessionId, relativePath));
    }

    public void writeSessionMeta(String sessionId, String content) {
        minioStorageService.saveBytes(buildSessionDir(sessionId), null, TestReportMultiConst.STORAGE_SESSION_META_FILE_NAME,
                content == null ? new byte[0] : content.getBytes(StandardCharsets.UTF_8), MediaType.APPLICATION_JSON_VALUE, true);
    }

    public String readSessionMeta(String sessionId) {
        String objectName = buildSessionMetaObjectName(sessionId);
        if (!minioStorageService.exists(objectName)) {
            return null;
        }
        return new String(minioStorageService.readBytes(objectName), StandardCharsets.UTF_8);
    }

    public byte[] readSessionZipBytes(String zipStoragePath) {
        return minioStorageService.readBytes(zipStoragePath);
    }

    public String saveTaskZipBytes(String multiId, String fileName, byte[] content) {
        return minioStorageService.saveBytes(buildTaskDir(multiId, TestReportMultiConst.STORAGE_MULTI_ZIP_DIR),
                null, fileName, content, "application/zip", false).getObjectName();
    }

    public String saveTaskSummaryBytes(String multiId, String fileName, byte[] content) {
        return minioStorageService.saveBytes(buildTaskDir(multiId, TestReportMultiConst.STORAGE_MULTI_SUMMARY_DIR),
                null, fileName, content, resolveExcelContentType(fileName), false).getObjectName();
    }

    public List<String> listTaskChildReportObjectNames(String multiId) {
        return minioStorageService.listObjectNames(buildTaskChildReportDir(multiId));
    }

    public List<String> listTaskSummaryObjectNames(String multiId) {
        return minioStorageService.listObjectNames(buildTaskSummaryDir(multiId));
    }

    public byte[] readStoredBytes(String objectName) {
        return minioStorageService.readBytes(objectName);
    }

    public String buildTaskChildReportDir(String multiId) {
        return buildTaskDir(multiId, TestReportMultiConst.STORAGE_MULTI_CHILD_REPORT_DIR);
    }

    public String buildTaskSummaryDir(String multiId) {
        return buildTaskDir(multiId, TestReportMultiConst.STORAGE_MULTI_SUMMARY_DIR);
    }

    public void deleteSessionQuietly(String sessionId) {
        deletePrefixQuietly(buildSessionDir(sessionId));
    }

    public void deleteQuietly(String storedPath) {
        minioStorageService.deleteQuietly(storedPath);
    }

    private void validateZipFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(CommonResponseEnum.FAIL, "压缩包不能为空");
        }
        String fileName = file.getOriginalFilename();
        if (StrUtil.isBlank(fileName) || !fileName.trim().toLowerCase().endsWith(".zip")) {
            throw new BusinessException(CommonResponseEnum.FAIL, "仅支持上传zip压缩包");
        }
    }

    private void deletePrefixQuietly(String prefix) {
        List<String> objectNames = minioStorageService.listObjectNames(prefix);
        for (String objectName : objectNames) {
            minioStorageService.deleteQuietly(objectName);
        }
    }

    private String resolveExcelContentType(String fileName) {
        return fileName != null && fileName.toLowerCase().endsWith(".xls")
                ? "application/vnd.ms-excel"
                : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    }

    private String buildSessionDir(String sessionId) {
        return AiReportFileConst.BIZ_DIR_TEST_REPORT + "/" + TestReportMultiConst.STORAGE_MULTI_SESSION_DIR + "/" + sessionId;
    }

    private String buildSessionZipDir(String sessionId) {
        return buildSessionDir(sessionId) + "/" + TestReportMultiConst.STORAGE_SESSION_ZIP_DIR;
    }

    private String buildSessionExtractDir(String sessionId, String parentPath) {
        String dir = buildSessionDir(sessionId) + "/" + TestReportMultiConst.STORAGE_SESSION_EXTRACT_DIR;
        return StrUtil.isBlank(parentPath) ? dir : dir + "/" + parentPath;
    }

    private String buildSessionExtractObjectName(String sessionId, String relativePath) {
        return buildSessionDir(sessionId) + "/" + TestReportMultiConst.STORAGE_SESSION_EXTRACT_DIR + "/" + normalizeRelativePath(relativePath);
    }

    private String buildSessionMetaObjectName(String sessionId) {
        return buildSessionDir(sessionId) + "/" + TestReportMultiConst.STORAGE_SESSION_META_FILE_NAME;
    }

    private String buildTaskDir(String multiId, String childDir) {
        return AiReportFileConst.BIZ_DIR_TEST_REPORT + "/" + TestReportMultiConst.STORAGE_MULTI_TASK_DIR + "/" + multiId + "/" + childDir;
    }

    private String resolveParentPath(String relativePath) {
        int index = relativePath.lastIndexOf('/');
        return index < 0 ? "" : relativePath.substring(0, index);
    }

    private String resolveFileName(String relativePath) {
        int index = relativePath.lastIndexOf('/');
        return index < 0 ? relativePath : relativePath.substring(index + 1);
    }

    private String normalizeRelativePath(String relativePath) {
        String normalized = StrUtil.trimToEmpty(relativePath).replace("\\", "/");
        while (normalized.startsWith("/")) {
            normalized = normalized.substring(1);
        }
        while (normalized.endsWith("/")) {
            normalized = normalized.substring(0, normalized.length() - 1);
        }
        if (StrUtil.isBlank(normalized)) {
            throw new BusinessException(CommonResponseEnum.FAIL, "压缩包内文件路径不能为空");
        }
        for (String segment : normalized.split("/")) {
            if (StrUtil.isBlank(segment) || ".".equals(segment) || "..".equals(segment)) {
                throw new BusinessException(CommonResponseEnum.FAIL, "压缩包内文件路径不合法");
            }
        }
        return normalized;
    }
}
