/**
 * Form Validation Module
 *
 * Provides reusable validation patterns for common form fields.
 *
 * Usage:
 *   import { validators, validateForm, addCustomValidator } from './modules/form-validation';
 *
 *   // Use pre-built validators
 *   if (!validators.email(email)) {
 *       showError('Invalid email');
 *   }
 *
 *   // Validate entire form
 *   const errors = validateForm('#customerForm', {
 *       email: ['required', 'email'],
 *       phone: ['required', 'phone'],
 *       gst: ['gst'],
 *       pan: ['pan']
 *   });
 */

/**
 * Pre-built validators
 */
export const validators = {
    /**
     * Check if value is not empty
     */
    required: (value) => {
        if (typeof value === 'string') {
            return value.trim() !== '';
        }
        return value !== null && value !== undefined;
    },

    /**
     * Validate email format
     */
    email: (value) => {
        if (!value) return true; // Use required for mandatory
        const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return pattern.test(value);
    },

    /**
     * Validate phone number (Indian format)
     */
    phone: (value) => {
        if (!value) return true;
        const pattern = /^[6-9]\d{9}$/;
        return pattern.test(value.replace(/\D/g, ''));
    },

    /**
     * Validate Indian GST number
     */
    gst: (value) => {
        if (!value) return true;
        const pattern = /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/;
        return pattern.test(value.toUpperCase());
    },

    /**
     * Validate Indian PAN number
     */
    pan: (value) => {
        if (!value) return true;
        const pattern = /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/;
        return pattern.test(value.toUpperCase());
    },

    /**
     * Validate minimum length
     */
    minLength: (value, min) => {
        if (!value) return true;
        return value.length >= min;
    },

    /**
     * Validate maximum length
     */
    maxLength: (value, max) => {
        if (!value) return true;
        return value.length <= max;
    },

    /**
     * Validate numeric value
     */
    numeric: (value) => {
        if (!value) return true;
        return !isNaN(parseFloat(value)) && isFinite(value);
    },

    /**
     * Validate positive number
     */
    positive: (value) => {
        if (!value) return true;
        return validators.numeric(value) && parseFloat(value) > 0;
    },

    /**
     * Validate minimum value
     */
    min: (value, min) => {
        if (!value) return true;
        return parseFloat(value) >= min;
    },

    /**
     * Validate maximum value
     */
    max: (value, max) => {
        if (!value) return true;
        return parseFloat(value) <= max;
    },

    /**
     * Validate date format (YYYY-MM-DD)
     */
    date: (value) => {
        if (!value) return true;
        const pattern = /^\d{4}-\d{2}-\d{2}$/;
        if (!pattern.test(value)) return false;
        const date = new Date(value);
        return date instanceof Date && !isNaN(date);
    },

    /**
     * Validate URL format
     */
    url: (value) => {
        if (!value) return true;
        try {
            new URL(value);
            return true;
        } catch {
            return false;
        }
    },

    /**
     * Validate file extension
     */
    fileExtension: (file, allowedExtensions) => {
        if (!file) return true;
        const fileName = file.name || file;
        const ext = fileName.split('.').pop().toLowerCase();
        return allowedExtensions.map(e => e.toLowerCase()).includes(ext);
    },

    /**
     * Validate file size (in MB)
     */
    fileSize: (file, maxSizeMB) => {
        if (!file) return true;
        return file.size <= maxSizeMB * 1024 * 1024;
    },

    /**
     * Match another field value
     */
    matches: (value, otherValue) => {
        return value === otherValue;
    }
};

/**
 * Error messages for validators
 */
const errorMessages = {
    required: 'This field is required.',
    email: 'Please enter a valid email address.',
    phone: 'Please enter a valid 10-digit phone number.',
    gst: 'Please enter a valid GST number.',
    pan: 'Please enter a valid PAN number.',
    minLength: 'Must be at least {0} characters.',
    maxLength: 'Must be no more than {0} characters.',
    numeric: 'Please enter a valid number.',
    positive: 'Please enter a positive number.',
    min: 'Value must be at least {0}.',
    max: 'Value must be no more than {0}.',
    date: 'Please enter a valid date.',
    url: 'Please enter a valid URL.',
    fileExtension: 'Invalid file type.',
    fileSize: 'File size must be less than {0}MB.',
    matches: 'Values do not match.'
};

/**
 * Add a custom validator
 *
 * @param {string} name - Validator name
 * @param {Function} fn - Validator function
 * @param {string} message - Error message
 */
export function addCustomValidator(name, fn, message) {
    validators[name] = fn;
    errorMessages[name] = message;
}

/**
 * Validate a form and return errors
 *
 * @param {string|HTMLFormElement} form - Form selector or element
 * @param {Object} rules - Validation rules { fieldName: ['required', 'email'] }
 * @returns {Object} - Errors object { fieldName: 'Error message' }
 */
export function validateForm(form, rules) {
    const $form = $(form);
    const errors = {};

    Object.entries(rules).forEach(([fieldName, fieldRules]) => {
        const $field = $form.find(`[name="${fieldName}"]`);
        let value = $field.val();

        // Handle checkbox/radio
        if ($field.attr('type') === 'checkbox' || $field.attr('type') === 'radio') {
            value = $field.is(':checked') ? $field.val() : null;
        }

        // Handle file input
        if ($field.attr('type') === 'file') {
            value = $field[0]?.files?.[0];
        }

        for (const rule of fieldRules) {
            let ruleName = rule;
            let ruleParams = [];

            // Handle rules with parameters (e.g., 'minLength:5')
            if (typeof rule === 'string' && rule.includes(':')) {
                const parts = rule.split(':');
                ruleName = parts[0];
                ruleParams = parts.slice(1);
            }

            // Get validator function
            const validator = validators[ruleName];
            if (!validator) continue;

            // Run validation
            const isValid = validator(value, ...ruleParams);
            if (!isValid) {
                // Get error message and replace placeholders
                let message = errorMessages[ruleName] || `Invalid ${fieldName}`;
                ruleParams.forEach((param, i) => {
                    message = message.replace(`{${i}}`, param);
                });
                errors[fieldName] = message;
                break; // Stop at first error for this field
            }
        }
    });

    return errors;
}

/**
 * Display validation errors on form
 *
 * @param {string|HTMLFormElement} form - Form selector or element
 * @param {Object} errors - Errors object from validateForm()
 */
export function showFormErrors(form, errors) {
    const $form = $(form);

    // Clear previous errors
    $form.find('.is-invalid').removeClass('is-invalid');
    $form.find('.invalid-feedback').remove();

    // Show new errors
    Object.entries(errors).forEach(([fieldName, message]) => {
        const $field = $form.find(`[name="${fieldName}"]`);
        $field.addClass('is-invalid');
        $field.after(`<div class="invalid-feedback">${message}</div>`);
    });
}

/**
 * Clear form validation errors
 *
 * @param {string|HTMLFormElement} form - Form selector or element
 */
export function clearFormErrors(form) {
    const $form = $(form);
    $form.find('.is-invalid').removeClass('is-invalid');
    $form.find('.invalid-feedback').remove();
}

/**
 * Setup real-time validation for a form
 *
 * @param {string|HTMLFormElement} form - Form selector or element
 * @param {Object} rules - Validation rules
 */
export function setupRealtimeValidation(form, rules) {
    const $form = $(form);

    Object.keys(rules).forEach(fieldName => {
        const $field = $form.find(`[name="${fieldName}"]`);

        $field.on('blur change', function() {
            const fieldErrors = validateForm(form, { [fieldName]: rules[fieldName] });

            // Clear previous error
            $field.removeClass('is-invalid');
            $field.siblings('.invalid-feedback').remove();

            // Show error if any
            if (fieldErrors[fieldName]) {
                $field.addClass('is-invalid');
                $field.after(`<div class="invalid-feedback">${fieldErrors[fieldName]}</div>`);
            }
        });
    });

    // Validate on submit
    $form.on('submit', function(e) {
        const errors = validateForm(form, rules);
        if (Object.keys(errors).length > 0) {
            e.preventDefault();
            showFormErrors(form, errors);
            return false;
        }
    });
}

export default {
    validators,
    addCustomValidator,
    validateForm,
    showFormErrors,
    clearFormErrors,
    setupRealtimeValidation
};
