/**
 * Alpine.js Components for enviPath
 *
 * This module provides reusable Alpine.js data components for modals,
 * form validation, and form submission.
 */

document.addEventListener('alpine:init', () => {
  /**
   * Modal Form Component
   *
   * Provides form validation using HTML5 Constraint Validation API,
   * loading states for submission, and error message management.
   *
   * Basic Usage:
   * <dialog x-data="modalForm()" @close="reset()">
   *   <form id="my-form">
   *     <input name="field" required>
   *   </form>
   *   <button @click="submit('my-form')" :disabled="isSubmitting">Submit</button>
   * </dialog>
   *
   * With Custom State:
   * <dialog x-data="modalForm({ state: { selectedItem: '', imageUrl: '' } })" @close="reset()">
   *   <select x-model="selectedItem" @change="updateImagePreview(selectedItem + '?image=svg')">
   *   <img :src="imageUrl" x-show="imageUrl">
   * </dialog>
   *
   * With AJAX:
   * <button @click="submitAsync('my-form', { onSuccess: (data) => console.log(data) })">
   */
  Alpine.data('modalForm', (options = {}) => ({
    isSubmitting: false,
    errors: {},
    // Spread custom initial state from options
    ...(options.state || {}),

    /**
     * Validate a single field using HTML5 Constraint Validation API
     * @param {HTMLElement} field - The input/select/textarea element
     */
    validateField(field) {
      const name = field.name || field.id;
      if (!name) return;

      if (!field.validity.valid) {
        this.errors[name] = field.validationMessage;
      } else {
        delete this.errors[name];
      }
    },

    /**
     * Clear error for a field (call on input)
     * @param {HTMLElement} field - The input element
     */
    clearError(field) {
      const name = field.name || field.id;
      if (name && this.errors[name]) {
        delete this.errors[name];
      }
    },

    /**
     * Get error message for a field
     * @param {string} name - Field name
     * @returns {string|undefined} Error message or undefined
     */
    getError(name) {
      return this.errors[name];
    },

    /**
     * Check if form has any errors
     * @returns {boolean} True if there are errors
     */
    hasErrors() {
      return Object.keys(this.errors).length > 0;
    },

    /**
     * Validate all fields in a form
     * @param {string} formId - The form element ID
     * @returns {boolean} True if form is valid
     */
    validateAll(formId) {
      const form = document.getElementById(formId);
      if (!form) return false;

      this.errors = {};
      const fields = form.querySelectorAll('input, select, textarea');

      fields.forEach(field => {
        if (field.name && !field.validity.valid) {
          this.errors[field.name] = field.validationMessage;
        }
      });

      return !this.hasErrors();
    },

    /**
     * Validate that two password fields match
     * @param {string} password1Id - ID of first password field
     * @param {string} password2Id - ID of second password field
     * @returns {boolean} True if passwords match
     */
    validatePasswordMatch(password1Id, password2Id) {
      const pw1 = document.getElementById(password1Id);
      const pw2 = document.getElementById(password2Id);

      if (!pw1 || !pw2) return false;

      if (pw1.value !== pw2.value) {
        this.errors[pw2.name || password2Id] = 'Passwords do not match';
        pw2.setCustomValidity('Passwords do not match');
        return false;
      }

      delete this.errors[pw2.name || password2Id];
      pw2.setCustomValidity('');
      return true;
    },

    /**
     * Submit a form with loading state
     * @param {string} formId - The form element ID
     */
    submit(formId) {
      const form = document.getElementById(formId);
      if (!form) return;

      // Validate before submit
      if (!form.checkValidity()) {
        form.reportValidity();
        return;
      }

      // Set action to current URL if empty
      if (!form.action || form.action === window.location.href + '#') {
        form.action = window.location.href;
      }

      // Set loading state and submit
      this.isSubmitting = true;
      form.submit();
    },

    /**
     * Submit form via AJAX (fetch)
     * @param {string} formId - The form element ID
     * @param {Object} options - Options { onSuccess, onError, closeOnSuccess }
     */
    async submitAsync(formId, options = {}) {
      const form = document.getElementById(formId);
      if (!form) return;

      // Validate before submit
      if (!form.checkValidity()) {
        form.reportValidity();
        return;
      }

      this.isSubmitting = true;

      try {
        const formData = new FormData(form);
        const response = await fetch(form.action || window.location.href, {
          method: form.method || 'POST',
          body: formData,
          headers: {
            'X-Requested-With': 'XMLHttpRequest',
          },
        });

        const data = await response.json().catch(() => ({}));

        if (response.ok) {
          if (options.onSuccess) {
            options.onSuccess(data);
          }

          if (data.redirect || data.success) {
            window.location.href = data.redirect || data.success;
          } else if (options.closeOnSuccess) {
            this.$el.closest('dialog')?.close();
          }
        } else {
          const errorMsg = data.error || data.message || `Error: ${response.status}`;
          this.errors['_form'] = errorMsg;

          if (options.onError) {
            options.onError(errorMsg, data);
          }
        }
      } catch (error) {
        this.errors['_form'] = error.message;

        if (options.onError) {
          options.onError(error.message);
        }
      } finally {
        this.isSubmitting = false;
      }
    },

    /**
     * Set form action URL dynamically
     * @param {string} formId - The form element ID
     * @param {string} url - The URL to set as action
     */
    setFormAction(formId, url) {
      const form = document.getElementById(formId);
      if (form) {
        form.action = url;
      }
    },

    /**
     * Update image preview
     * @param {string} url - Image URL (with query params)
     * @param {string} targetId - Target element ID for the image
     */
    updateImagePreview(url) {
      // Store URL for reactive binding with :src
      this.imageUrl = url;
    },

    /**
     * Reset form state (call on modal close)
     * Resets to initial state from options
     */
    reset() {
      this.isSubmitting = false;
      this.errors = {};
      this.imageUrl = '';

      // Reset custom state to initial values
      if (options.state) {
        Object.keys(options.state).forEach(key => {
          this[key] = options.state[key];
        });
      }

      // Call custom reset handler if provided
      if (options.onReset) {
        options.onReset.call(this);
      }
    }
  }));

  /**
   * Simple Modal Component (no form)
   *
   * For modals that don't need form validation.
   *
   * Usage:
   * <dialog x-data="modal()">
   *   <button @click="$el.closest('dialog').close()">Close</button>
   * </dialog>
   */
  Alpine.data('modal', () => ({
    // Placeholder for simple modals that may need state later
  }));
});
