/**
 * Path Validator
 * 路径验证器
 *
 * Validates and sanitizes asset paths for security
 * 验证并清理资产路径以确保安全
 */

export class PathValidator {
    // Dangerous path patterns
    private static readonly DANGEROUS_PATTERNS = [
        /\.\.[/\\]/g,  // Path traversal attempts (..)
        /^[/\\]/,      // Absolute paths on Unix
        /^[a-zA-Z]:[/\\]/,  // Absolute paths on Windows
        /[<>:"|?*]/,    // Invalid characters for Windows paths
        /\0/,           // Null bytes
        /%00/,          // URL encoded null bytes
        /\.\.%2[fF]/   // URL encoded path traversal
    ];

    // Valid path characters (alphanumeric, dash, underscore, dot, slash)
    private static readonly VALID_PATH_REGEX = /^[a-zA-Z0-9\-_./\\@]+$/;

    // Maximum path length
    private static readonly MAX_PATH_LENGTH = 260;

    /**
     * Validate if a path is safe
     * 验证路径是否安全
     */
    static validate(path: string): { valid: boolean; reason?: string } {
        // Check for null/undefined/empty
        if (!path || typeof path !== 'string') {
            return { valid: false, reason: 'Path is empty or invalid' };
        }

        // Check length
        if (path.length > this.MAX_PATH_LENGTH) {
            return { valid: false, reason: `Path exceeds maximum length of ${this.MAX_PATH_LENGTH} characters` };
        }

        // Check for dangerous patterns
        for (const pattern of this.DANGEROUS_PATTERNS) {
            if (pattern.test(path)) {
                return { valid: false, reason: 'Path contains dangerous pattern' };
            }
        }

        // Check for valid characters
        if (!this.VALID_PATH_REGEX.test(path)) {
            return { valid: false, reason: 'Path contains invalid characters' };
        }

        return { valid: true };
    }

    /**
     * Sanitize a path
     * 清理路径
     */
    static sanitize(path: string): string {
        if (!path || typeof path !== 'string') {
            return '';
        }

        // Remove dangerous patterns
        let sanitized = path;

        // Remove path traversal (apply repeatedly until fully removed)
        let prev;
        do {
            prev = sanitized;
            sanitized = sanitized.replace(/\.\.[/\\]/g, '');
        } while (sanitized !== prev);

        // Remove leading slashes
        sanitized = sanitized.replace(/^[/\\]+/, '');

        // Remove null bytes
        sanitized = sanitized.replace(/\0/g, '');
        sanitized = sanitized.replace(/%00/g, '');

        // Remove invalid Windows characters
        sanitized = sanitized.replace(/[<>:"|?*]/g, '_');

        // Normalize slashes
        sanitized = sanitized.replace(/\\/g, '/');

        // Remove double slashes
        sanitized = sanitized.replace(/\/+/g, '/');

        // Trim whitespace
        sanitized = sanitized.trim();

        // Truncate if too long
        if (sanitized.length > this.MAX_PATH_LENGTH) {
            sanitized = sanitized.substring(0, this.MAX_PATH_LENGTH);
        }

        return sanitized;
    }

    /**
     * Check if path is trying to escape the base directory
     * 检查路径是否试图逃离基础目录
     */
    static isPathTraversal(path: string): boolean {
        const normalized = path.replace(/\\/g, '/');
        return normalized.includes('../') || normalized.includes('..\\');
    }

    /**
     * Normalize a path for consistent handling
     * 规范化路径以便一致处理
     */
    static normalize(path: string): string {
        if (!path) return '';

        // Sanitize first
        let normalized = this.sanitize(path);

        // Convert backslashes to forward slashes
        normalized = normalized.replace(/\\/g, '/');

        // Remove trailing slash (except for root)
        if (normalized.length > 1 && normalized.endsWith('/')) {
            normalized = normalized.slice(0, -1);
        }

        return normalized;
    }

    /**
     * Join path segments safely
     * 安全地连接路径段
     */
    static join(...segments: string[]): string {
        const validSegments = segments
            .filter((s) => s && typeof s === 'string')
            .map((s) => this.sanitize(s))
            .filter((s) => s.length > 0);

        if (validSegments.length === 0) {
            return '';
        }

        return this.normalize(validSegments.join('/'));
    }

    /**
     * Get file extension safely
     * 安全地获取文件扩展名
     */
    static getExtension(path: string): string {
        const sanitized = this.sanitize(path);
        const lastDot = sanitized.lastIndexOf('.');
        const lastSlash = sanitized.lastIndexOf('/');

        if (lastDot > lastSlash && lastDot > 0) {
            return sanitized.substring(lastDot + 1).toLowerCase();
        }

        return '';
    }
}
