/**
 * Form Validation Utility
 * Provides inline validation with ARIA support
 */
(function() {
    'use strict';

    /**
     * FormValidator class for managing form field validation
     */
    class FormValidator {
        constructor() {
            this.validators = new Map();
            this.errorElements = new Map();
        }

        /**
         * Add validation to a field
         * @param {HTMLElement|string} field - Field element or selector
         * @param {Function} validatorFn - Function that returns error message or null
         * @param {Object} options - Validation options
         * @param {boolean} options.validateOnBlur - Validate when field loses focus
         * @param {boolean} options.validateOnInput - Validate on input change
         */
        addValidation(field, validatorFn, options = {}) {
            const element = typeof field === 'string' ? document.querySelector(field) : field;
            if (!element) return;

            const { validateOnBlur = true, validateOnInput = false } = options;

            this.validators.set(element, validatorFn);

            // Ensure the field has an ID for aria-describedby
            if (!element.id) {
                element.id = `form-field-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
            }

            // Create error element
            const errorId = `${element.id}-error`;
            let errorElement = document.getElementById(errorId);
            if (!errorElement) {
                errorElement = document.createElement('div');
                errorElement.id = errorId;
                errorElement.className = 'ldr-field-error';
                errorElement.setAttribute('aria-live', 'polite');
                element.parentNode.insertBefore(errorElement, element.nextSibling);
            }
            this.errorElements.set(element, errorElement);

            // Set up aria-describedby
            const existingDescribedBy = element.getAttribute('aria-describedby');
            if (!existingDescribedBy || !existingDescribedBy.includes(errorId)) {
                element.setAttribute('aria-describedby',
                    existingDescribedBy ? `${existingDescribedBy} ${errorId}` : errorId);
            }

            // Add event listeners
            if (validateOnBlur) {
                element.addEventListener('blur', () => this.validateField(element));
            }
            if (validateOnInput) {
                element.addEventListener('input', () => this.validateField(element));
            }
        }

        /**
         * Validate a single field
         * @param {HTMLElement} element - The field to validate
         * @returns {boolean} - Whether the field is valid
         */
        validateField(element) {
            const validatorFn = this.validators.get(element);
            const errorElement = this.errorElements.get(element);

            if (!validatorFn) return true;

            const errorMessage = validatorFn(element.value, element);

            if (errorMessage) {
                element.classList.add('ldr-field-invalid');
                element.setAttribute('aria-invalid', 'true');
                if (errorElement) {
                    errorElement.textContent = errorMessage;
                    errorElement.style.display = 'block';
                }
                return false;
            }
            element.classList.remove('ldr-field-invalid');
            element.removeAttribute('aria-invalid');
            if (errorElement) {
                errorElement.textContent = '';
                errorElement.style.display = 'none';
            }
            return true;
        }

        /**
         * Validate all registered fields
         * @returns {boolean} - Whether all fields are valid
         */
        validateAll() {
            let allValid = true;
            this.validators.forEach((_, element) => {
                if (!this.validateField(element)) {
                    allValid = false;
                }
            });
            return allValid;
        }

        /**
         * Clear all validation errors
         */
        clearErrors() {
            this.validators.forEach((_, element) => {
                element.classList.remove('ldr-field-invalid');
                element.removeAttribute('aria-invalid');
                const errorElement = this.errorElements.get(element);
                if (errorElement) {
                    errorElement.textContent = '';
                    errorElement.style.display = 'none';
                }
            });
        }

        /**
         * Show error on a specific field
         * @param {HTMLElement|string} field - Field element or selector
         * @param {string} message - Error message to display
         */
        showError(field, message) {
            const element = typeof field === 'string' ? document.querySelector(field) : field;
            if (!element) return;

            const errorElement = this.errorElements.get(element);
            element.classList.add('ldr-field-invalid');
            element.setAttribute('aria-invalid', 'true');
            if (errorElement) {
                errorElement.textContent = message;
                errorElement.style.display = 'block';
            }
        }
    }

    // Common validators
    const validators = {
        required: (message = 'This field is required') => (value) => {
            return value && value.trim() ? null : message;
        },
        minLength: (min, message) => (value) => {
            if (!value) return null; // Let required handle empty
            return value.length >= min ? null : (message || `Must be at least ${min} characters`);
        },
        maxLength: (max, message) => (value) => {
            if (!value) return null;
            return value.length <= max ? null : (message || `Must be no more than ${max} characters`);
        },
        pattern: (regex, message) => (value) => {
            if (!value) return null;
            return regex.test(value) ? null : (message || 'Invalid format');
        }
    };

    // Export to window
    window.FormValidator = FormValidator;
    window.formValidators = validators;
})();
