package com.njcn.rdms.module.project.framework.attachment;

import com.njcn.rdms.module.project.dal.dataobject.attachment.AttachmentItem;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Locale;
import java.util.Set;

import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 附件统一校验。任务、工时（以及未来的产品需求 / 项目需求 / 工单）共用。
 * <p>
 * 规则：
 * <ul>
 *   <li>列表数量 ≤ {@link #MAX_COUNT}</li>
 *   <li>id：允许为空；新上传文件建议传 rdms-system 文件上传返回的 data.id</li>
 *   <li>url：非空、{@code http://} 或 {@code https://} 开头、长度 ≤ {@link #MAX_URL_LENGTH}</li>
 *   <li>name：非空、长度 ≤ {@link #MAX_NAME_LENGTH}</li>
 *   <li>扩展名（取自 name 最末一段，小写比对）必须在 {@link #ALLOWED_EXTENSIONS}，且不能在 {@link #BLOCKED_EXTENSIONS}</li>
 * </ul>
 * 单文件大小限制依赖 {@code /system/file/upload} 上传时拦截，本类不复核。
 */
public final class AttachmentValidator {

    public static final int MAX_COUNT = 20;
    public static final int MAX_URL_LENGTH = 1024;
    public static final int MAX_NAME_LENGTH = 255;

    /** 允许的扩展名白名单（小写，无 {@code .}）。 */
    public static final Set<String> ALLOWED_EXTENSIONS = Set.of(
            // 文档
            "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md", "csv",
            // 图片
            "jpg", "jpeg", "png", "gif", "webp", "bmp",
            // 压缩
            "zip", "rar", "7z",
            // 媒体
            "mp4", "mp3",
            // 其他
            "sql", "xml", "json"
    );

    /** 禁止的扩展名黑名单（即使在白名单也禁，兜底防可执行 / 脚本类）。 */
    public static final Set<String> BLOCKED_EXTENSIONS = Set.of(
            "exe", "bat", "cmd", "sh", "ps1", "msi", "dll", "jar", "war",
            "php", "jsp", "asp", "aspx", "py", "rb", "pl",
            "com", "scr", "vbs", "js"
    );

    private AttachmentValidator() {
    }

    public static void validate(List<AttachmentItem> attachments) {
        if (attachments == null || attachments.isEmpty()) {
            return;
        }
        if (attachments.size() > MAX_COUNT) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_TOO_MANY, MAX_COUNT);
        }
        for (AttachmentItem item : attachments) {
            validateItem(item);
        }
    }

    private static void validateItem(AttachmentItem item) {
        if (item == null) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_NAME_INVALID);
        }
        // url：协议 + 长度
        String url = item.getUrl();
        if (!StringUtils.hasText(url) || url.length() > MAX_URL_LENGTH
                || !(url.startsWith("http://") || url.startsWith("https://"))) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_URL_INVALID);
        }
        // name：非空 + 长度
        String name = item.getName();
        if (!StringUtils.hasText(name) || name.length() > MAX_NAME_LENGTH) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_NAME_INVALID);
        }
        // 扩展名：黑名单优先，再过白名单
        String ext = extractExtension(name);
        if (BLOCKED_EXTENSIONS.contains(ext)) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_TYPE_BLOCKED, ext);
        }
        if (!ALLOWED_EXTENSIONS.contains(ext)) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_ATTACHMENT_TYPE_NOT_ALLOWED, ext);
        }
    }

    private static String extractExtension(String name) {
        int dot = name.lastIndexOf('.');
        if (dot < 0 || dot == name.length() - 1) {
            return "";
        }
        return name.substring(dot + 1).toLowerCase(Locale.ROOT);
    }
}
