/**
 * URL Validation Utilities
 * Provides secure URL validation to prevent XSS attacks
 */

const URLValidator = {
    UNSAFE_SCHEMES: ['javascript', 'data', 'vbscript', 'about', 'blob', 'file'],
    SAFE_SCHEMES: ['http', 'https', 'ftp', 'ftps'],
    EMAIL_SCHEME: 'mailto',

    isUnsafeScheme: function(url) {
        if (!url) return false;

        const normalizedUrl = url.trim().toLowerCase();

        for (const scheme of this.UNSAFE_SCHEMES) {
            if (normalizedUrl.startsWith(scheme + ':')) {
                console.warn(`Unsafe URL scheme detected: ${scheme}`);
                return true;
            }
        }

        return false;
    },

    isSafeUrl: function(url, options = {}) {
        const {
            requireScheme = true,
            allowFragments = true,
            allowMailto = false,
            trustedDomains = []
        } = options;

        if (!url || typeof url !== 'string') {
            return false;
        }

        // Check for unsafe schemes first
        if (this.isUnsafeScheme(url)) {
            return false;
        }

        // Handle fragment-only URLs
        if (url.startsWith('#')) {
            return allowFragments;
        }

        // Parse the URL
        try {
            const parsed = new URL(url, window.location.href);
            const scheme = parsed.protocol.slice(0, -1).toLowerCase(); // Remove trailing ':'

            // Check if it's a mailto link
            if (scheme === this.EMAIL_SCHEME) {
                return allowMailto;
            }

            // Check if it's a safe scheme
            if (!this.SAFE_SCHEMES.includes(scheme)) {
                console.warn(`Unsafe URL scheme: ${scheme}`);
                return false;
            }

            // Validate domain if trusted domains are specified
            if (trustedDomains.length > 0 && parsed.hostname) {
                const hostname = parsed.hostname.toLowerCase();
                const isTrusted = trustedDomains.some(domain =>
                    hostname === domain.toLowerCase() ||
                    hostname.endsWith('.' + domain.toLowerCase())
                );

                if (!isTrusted) {
                    console.warn(`URL domain not in trusted list: ${parsed.hostname}`);
                    return false;
                }
            }

            return true;
        } catch (e) {
            console.warn(`Failed to parse URL: ${e.message}`);
            return false;
        }
    },

    sanitizeUrl: function(url, defaultScheme = 'https') {
        if (!url) return null;

        // Check for unsafe schemes
        if (this.isUnsafeScheme(url)) {
            return null;
        }

        // Strip whitespace
        url = url.trim();

        // Add scheme if missing
        if (!url.match(/^[a-zA-Z][a-zA-Z\d+\-.]*:/)) {
            url = `${defaultScheme}://${url}`;
        }

        // Validate the final URL
        if (this.isSafeUrl(url, { requireScheme: true })) {
            return url;
        }

        return null;
    },

    /**
     * Safe URL assignment with validation
     * Use this for any dynamic URL assignments
     */
    safeAssign: function(element, property, url, options = {}) {
        // Special handling for internal navigation
        if (url && (url.startsWith('/') || url.startsWith('#'))) {
            element[property] = url;
            return true;
        }

        // Special handling for blob and data URLs (safe for downloads)
        if (url && (url.startsWith('blob:') || url.startsWith('data:'))) {
            element[property] = url;
            return true;
        }

        // Validate external URLs
        if (this.isSafeUrl(url, options)) {
            element[property] = url;
            return true;
        }

        console.warn(`Blocked unsafe URL assignment: ${url}`);
        return false;
    }
};

// Export for use in other files
if (typeof module !== 'undefined' && module.exports) {
    module.exports = URLValidator;
}

// Make URLValidator available globally for browser usage
if (typeof window !== 'undefined') {
    window.URLValidator = URLValidator;
}
