package com.easyagents.skill.util;

import com.easyagents.skill.exception.SkillValidationException;

import java.text.Normalizer;
import java.util.Locale;

/**
 * Skill 逻辑路径工具。
 */
public final class SkillPaths {

    /**
     * Skill 主文件名。
     */
    public static final String SKILL_FILE = "SKILL.md";

    /**
     * reference 顶级目录。
     */
    public static final String REFERENCES_DIR = "references";

    /**
     * script 顶级目录。
     */
    public static final String SCRIPTS_DIR = "scripts";

    /**
     * asset 顶级目录。
     */
    public static final String ASSETS_DIR = "assets";

    /**
     * example 顶级目录。
     */
    public static final String EXAMPLES_DIR = "examples";

    private SkillPaths() {
    }

    /**
     * 规范化逻辑路径。
     *
     * @param path 原始路径
     * @return 规范化后的路径
     */
    public static String normalize(String path) {
        return normalize(path, false);
    }

    /**
     * 规范化已识别的系统元数据路径，允许其中保留隐藏路径段供导入器安全忽略。
     *
     * @param path 原始系统元数据路径
     * @return 规范化后的系统元数据路径
     * @throws SkillValidationException 路径不属于可忽略系统元数据或包含不安全路径段时抛出
     */
    public static String normalizeIgnoredSystemPath(String path) {
        if (!isIgnoredSystemPath(path)) {
            throw new SkillValidationException("Skill path is not ignored system metadata: " + path);
        }
        return normalize(path, true);
    }

    /**
     * 规范化逻辑路径并按用途控制隐藏路径段。
     *
     * @param path 原始路径
     * @param allowHiddenSegments 是否允许隐藏路径段
     * @return 规范化后的路径
     * @throws SkillValidationException 路径非法时抛出
     */
    private static String normalize(String path, boolean allowHiddenSegments) {
        if (path == null) {
            throw new SkillValidationException("Skill path is required.");
        }
        if (containsControlCharacter(path)) {
            throw new SkillValidationException("Skill path contains a control character.");
        }
        String normalized = Normalizer.normalize(path.replace('\\', '/'), Normalizer.Form.NFC);
        if (normalized.isEmpty()) {
            throw new SkillValidationException("Skill path cannot be empty.");
        }
        if (normalized.startsWith("/") || normalized.matches("^[A-Za-z]:.*")) {
            throw new SkillValidationException("Absolute skill path is not allowed: " + path);
        }
        String[] segments = normalized.split("/", -1);
        for (String segment : segments) {
            if (segment.isEmpty() || ".".equals(segment) || "..".equals(segment)) {
                throw new SkillValidationException("Unsafe skill path is not allowed: " + path);
            }
            if (!allowHiddenSegments && segment.startsWith(".")) {
                throw new SkillValidationException("Hidden skill path is not allowed: " + path);
            }
            if (!segment.equals(segment.strip())) {
                throw new SkillValidationException("Skill path segments cannot have surrounding whitespace: " + path);
            }
        }
        return normalized;
    }

    /**
     * 生成大小写不敏感的路径冲突键。
     *
     * @param path 逻辑路径
     * @return 路径冲突键
     */
    public static String collisionKey(String path) {
        return normalize(path).toLowerCase(Locale.ROOT);
    }

    /**
     * 获取路径段数量。
     *
     * @param path 逻辑路径
     * @return 路径深度
     */
    public static int depth(String path) {
        return normalize(path).split("/", -1).length;
    }

    /**
     * 获取一级目录或文件名。
     *
     * @param path 逻辑路径
     * @return 一级路径段
     */
    public static String firstSegment(String path) {
        String normalized = normalize(path);
        int index = normalized.indexOf('/');
        return index < 0 ? normalized : normalized.substring(0, index);
    }

    /**
     * 获取文件名。
     *
     * @param path 逻辑路径
     * @return 文件名
     */
    public static String fileName(String path) {
        String normalized = normalize(path);
        int index = normalized.lastIndexOf('/');
        return index < 0 ? normalized : normalized.substring(index + 1);
    }

    /**
     * 判断扩展名是否匹配。
     *
     * @param path 逻辑路径
     * @param extension 扩展名
     * @return 匹配时为 true
     */
    public static boolean hasExtension(String path, String extension) {
        return normalize(path).toLowerCase(Locale.ROOT).endsWith(extension.toLowerCase(Locale.ROOT));
    }

    /**
     * 判断是否为系统文件路径。
     *
     * @param path 原始路径
     * @return 系统文件时为 true
     */
    public static boolean isIgnoredSystemPath(String path) {
        if (path == null) {
            return true;
        }
        String normalized = path.replace('\\', '/');
        return normalized.startsWith("__MACOSX/")
                || normalized.contains("/__MACOSX/")
                || normalized.endsWith("/.DS_Store")
                || ".DS_Store".equals(normalized);
    }

    private static boolean containsControlCharacter(String path) {
        for (int index = 0; index < path.length(); index++) {
            char character = path.charAt(index);
            if (character <= 0x1F || character == 0x7F
                    || Character.getType(character) == Character.FORMAT) {
                return true;
            }
        }
        return false;
    }
}
