package com.njcn.gather.tools.report.util;

import cn.hutool.core.util.StrUtil;

/**
 * 文件路径片段净化工具。
 * <p>
 * 用于把外部输入（数据库中的设备型号名、计划名等）作为目录或文件名片段拼入磁盘路径前的兜底清洗，
 * 防止 {@code /} {@code \} {@code ..} {@code :} 等路径敏感字符导致：
 * <ul>
 *   <li>报告文件被写到预期目录之外（路径穿越）</li>
 *   <li>名字含 {@code /} 时被操作系统解释成多级子目录（即使无恶意，自然命名如"高/中压"也会触发）</li>
 *   <li>Windows 上 {@code :} 触发 NTFS 备用数据流</li>
 *   <li>文件创建失败抛 IO 异常</li>
 * </ul>
 *
 * @author hongawen
 */
public final class FilePathSanitizer {

    /**
     * Windows + Linux 共同非法字符 + 控制字符：替换为下划线
     */
    private static final String UNSAFE_CHAR_PATTERN = "[\\\\/:*?\"<>|\\x00-\\x1F]";

    private FilePathSanitizer() {
    }

    /**
     * 把一段字符串净化成可安全拼入磁盘路径的片段。
     * <p>
     * 规则：
     * <ol>
     *   <li>{@code null} 或全空白 → 返回 {@code "_"}（保证拼出来的路径仍合法）</li>
     *   <li>{@code /} {@code \} {@code :} {@code *} {@code ?} {@code "} {@code <} {@code >} {@code |}
     *       及 ASCII 控制字符替换为 {@code _}</li>
     *   <li>把 {@code ..} 折叠为 {@code _}，防止路径穿越</li>
     *   <li>连续 {@code _} 合并为单个 {@code _}</li>
     *   <li>首尾空白与 {@code .} 去掉（Windows 不允许文件名以 {@code .} 结尾）</li>
     * </ol>
     *
     * @param raw 原始字符串
     * @return 净化后的片段；当输入合法且无危险字符时与原值一致
     */
    public static String toSafeFileName(String raw) {
        if (StrUtil.isBlank(raw)) {
            return "_";
        }
        String result = raw.replaceAll(UNSAFE_CHAR_PATTERN, "_");
        // 折叠路径穿越序列
        while (result.contains("..")) {
            result = result.replace("..", "_");
        }
        // 合并连续下划线
        result = result.replaceAll("_+", "_");
        // 去掉首尾空白和点
        result = result.replaceAll("^[\\s.]+|[\\s.]+$", "");
        return result.isEmpty() ? "_" : result;
    }
}
