// Toast Service
class ToastService {
  constructor(options = {}) {
    this.successToastEl = document.getElementById(
      options.successId || 'successToast'
    )
    this.warningToastEl = document.getElementById(
      options.warningId || 'warningToast'
    )

    this.successToast = this.successToastEl
      ? bootstrap.Toast.getOrCreateInstance(this.successToastEl)
      : null

    this.warningToast = this.warningToastEl
      ? bootstrap.Toast.getOrCreateInstance(this.warningToastEl)
      : null
  }

  show(type, message) {
    const toastEl =
      type === 'success' ? this.successToastEl : this.warningToastEl
    const toast = type === 'success' ? this.successToast : this.warningToast

    if (toastEl && toast) {
      const msgContainer = toastEl.querySelector('.toast-body')
      if (msgContainer) msgContainer.textContent = message
      toast.show()
    }
  }

  extractErrorMessage(html) {
    try {
      const parser = new DOMParser()
      const doc = parser.parseFromString(html, 'text/html')
      const p = doc.querySelector('.wp-die-message p')
      return p ? p.textContent : 'Unknown error occurred'
    } catch (e) {
      return 'Unexpected error'
    }
  }

  success(msg, timeout = 0, callback = null) {
    this.show('success', msg)
    if (timeout > 0) {
      setTimeout(() => {
        if (typeof callback === 'function') callback()
      }, timeout)
    }
  }

  error(msg, timeout = 0, callback = null) {
    this.show('error', msg)
    if (timeout > 0) {
      setTimeout(() => {
        if (typeof callback === 'function') callback()
      }, timeout)
    }
  }
}

// Global instance
window.ToastService = new ToastService()

function filterSidebarFormService(formEl) {
  if (!formEl) return;
  // Handle all <select> elements inside the form
  formEl.querySelectorAll('select').forEach(function (select) {
    select.addEventListener('change', function () {
      formEl.submit();
    });
  });
  // Handle all price range inputs inside the form
  formEl.querySelectorAll('[listar-price-range]').forEach((input) => {
    input.addEventListener('change', function (elm) {
      // --- Moved logic from listarSidebar.onPriceRangeChange ---
      const rangeElm = elm.target;
      const parentElm = rangeElm.closest('div');
      const unit = rangeElm.dataset.unit;
      const priceLabel = parentElm.querySelector('#priceRangeLabel');
      if (priceLabel) {
        priceLabel.innerHTML = unit + '' + rangeElm.value;
      }
      const url = new URL(location.href);
      url.searchParams.set('price', rangeElm.value);
      // Store chosen value for later use on Confirm
      rangeElm.dataset.chosen = rangeElm.value;
      const confirmBtn = parentElm.querySelector('#priceRangeConfirmBtn');
      if (confirmBtn) {
        // Unbind old listener by cloning and replacing the element
        const newBtn = confirmBtn.cloneNode(true);
        confirmBtn.parentNode.replaceChild(newBtn, confirmBtn);
        newBtn.addEventListener('click', () => {
          window.location.href = url.href;
        });
      }
      // --- End moved logic ---
    });
  });

  formEl.querySelectorAll('button[data-action="listar-price-input-confirm"]').forEach((button) => {
    button.addEventListener('click', function (elm) {
      // --- Moved logic from listarSidebar.onPriceInputConfirmBtn ---
      const buttonElm = elm.target;
      const parentElm = buttonElm.closest('aside');
      const url = new URL(location.href);
      const priceMaxInput = parentElm.querySelector('#priceMax');
      const priceMinInput = parentElm.querySelector('#priceMin');
      if (priceMaxInput && priceMinInput) {
        url.searchParams.set('price_max', priceMaxInput.value);
        url.searchParams.set('price_min', priceMinInput.value);
      }
      window.location.href = url.href;
      // --- End moved logic ---
    });
  });
}

function ListingFormService(formEl, options = {}) {
  if (!formEl) return;
  // Elements
  const country = formEl.querySelector('#country');
  const state = formEl.querySelector('#state');
  const city = formEl.querySelector('#city');
  const fileInput = formEl.querySelector('#listing-image');
  const uploadBox = formEl.querySelector('#custom-upload-box');
  const previewBox = formEl.querySelector('#custom-image-preview');
  const previewImg = formEl.querySelector('#listing-image-preview');
  const removeBtn = formEl.querySelector('#remove-image-btn');
  const saveBtn = formEl.querySelector('#listing-save-btn');
  const loadingIcon = formEl.querySelector('#listing-save-loading');
  const progressBarWrap = formEl.querySelector('#upload-progress-bar-wrap');
  const progressBar = formEl.querySelector('#upload-progress-bar');
  const formAction = formEl.getAttribute('data-action') || 'add';

  // Country > State > City dynamic loading
  if (country) {
    country.addEventListener('change', function () {
      let countryId = this.value;
      state.innerHTML = '<option value="">' + (options.textSelectState || 'Select State') + '</option>';
      city.innerHTML = '<option value="">' + (options.textSelectCity || 'Select City') + '</option>';
      if (countryId) {
        fetch(WP_API.rest_url + 'listar/v1/location/list/?parent_id=' + countryId)
          .then(res => res.json())
          .then(response => {
            if (response.success && Array.isArray(response.data)) {
              response.data.forEach(function (stateItem) {
                let opt = document.createElement('option');
                opt.value = stateItem.term_id;
                opt.textContent = stateItem.name;
                state.appendChild(opt);
              });
            } else {
              window.ToastService.error(response.message || (options.textFailedState || 'Failed to load states.'));
            }
          })
          .catch(() => {
            window.ToastService.error(options.textFailedState || 'Failed to load states.');
          });
      }
    });
  }

  if (state) {
    state.addEventListener('change', function () {
      let stateId = this.value;
      city.innerHTML = '<option value="">' + (options.textSelectCity || 'Select City') + '</option>';
      if (stateId) {
        fetch(WP_API.rest_url + 'listar/v1/location/list/?parent_id=' + stateId)
          .then(res => res.json())
          .then(response => {
            if (response.success && Array.isArray(response.data)) {
              response.data.forEach(function (cityItem) {
                let opt = document.createElement('option');
                opt.value = cityItem.term_id;
                opt.textContent = cityItem.name;
                city.appendChild(opt);
              });
            } else {
              window.ToastService.error(response.message || (options.textFailedCity || 'Failed to load cities.'));
            }
          })
          .catch(() => {
            window.ToastService.error(options.textFailedCity || 'Failed to load cities.');
          });
      }
    });
  }

  // Custom upload UI
  if (uploadBox && fileInput) {
    uploadBox.addEventListener('click', function () {
      fileInput.click();
    });
  }
  if (fileInput && previewBox && previewImg && uploadBox) {
    fileInput.addEventListener('change', function (e) {
      const file = e.target.files[0];
      if (file) {
        const reader = new FileReader();
        reader.onload = function (ev) {
          previewImg.src = ev.target.result;
          previewBox.style.display = 'block';
          previewBox.classList.remove('d-none');
          uploadBox.classList.add('d-none');
        };
        reader.readAsDataURL(file);
      }
    });
  }
  if (removeBtn && fileInput && previewBox && uploadBox && previewImg) {
    removeBtn.addEventListener('click', function (e) {
      e.preventDefault();
      fileInput.value = '';
      previewImg.src = '';
      previewBox.classList.add('d-none');
      uploadBox.classList.remove('d-none');
    });
  }

  // Add query selector for map picker
  const mapEl = document.querySelector('[listar-map-picker]');
  if (mapEl) {
      const map = new MapAdapter({
          element: mapEl,
          // provider: 'Leaflet', // or 'gmap'
          // center: [10.7763897, 106.7011391],
          // zoom: 14
      });
      map.enableClickSelect('#latitude', '#longitude');

      // If the form has latitude and longitude inputs, set the map view
      const lat = document.querySelector('#latitude').value;
      const lng = document.querySelector('#longitude').value;
      if (lat && lng) {
          map.addMarker(lat, lng);
          map.setView(lat, lng); // Default zoom level
      }
  } else {
      console.warn('No element with listar-map-picker attribute found.');
  }

  // Handle form save with AJAX and progress
  formEl.addEventListener('submit', function (e) {
    e.preventDefault();

    // Validate the form using built-in constraint validation API
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    let formData = new FormData(formEl);
    if (saveBtn) saveBtn.disabled = true;
    if (loadingIcon) loadingIcon.style.display = 'inline-block';
    if (progressBarWrap && progressBar) {
      progressBarWrap.style.display = 'block';
      progressBar.setAttribute('aria-valuenow', 0);
      progressBar.style.width = '0%';
      progressBar.textContent = '0%';
    }
    var xhr = new XMLHttpRequest();
    xhr.open('POST', WP_API.rest_url + 'listar/v1/place/save/', true);
    xhr.setRequestHeader('X-WP-Nonce', WP_API.nonce);
    xhr.withCredentials = true;
    xhr.upload.onprogress = function (e) {
      if (e.lengthComputable && progressBar) {
        var percent = Math.round((e.loaded / e.total) * 100);
        progressBar.style.width = percent + '%';
        progressBar.setAttribute('aria-valuenow', percent);
        progressBar.textContent = percent + '%';
      }
    };
    xhr.onload = function () {
      if (saveBtn) saveBtn.disabled = false;
      if (loadingIcon) loadingIcon.style.display = 'none';
      if (progressBarWrap && progressBar) {
        progressBarWrap.style.display = 'none';
        progressBar.style.width = '0%';
        progressBar.setAttribute('aria-valuenow', 0);
        progressBar.textContent = '0%';
      }
      let data;
      try { data = JSON.parse(xhr.responseText); } catch (e) { data = { success: false }; }
      if (data && data.success) {
        if (typeof options.onSuccess === 'function') {
          options.onSuccess(data, formEl);
        } else {
          window.ToastService.success(options.textSuccess || 'Listing saved successfully!', 2000, function () {
            if( formAction === 'add' && data.hasOwnProperty('links') && data.links && data.links.hasOwnProperty('dashboard_edit') ) {
              window.location.href = data.links.dashboard_edit;
            } else {
              // If no redirect link, just reload the page
              window.location.reload();
            }
          });
        }
        // formEl.reset();
      } else {
        if (typeof options.onError === 'function') options.onError(data, formEl);
        else window.ToastService.error((data && data.message) ? data.message : (options.textError || 'Error saving listing.'));
      }
    };
    xhr.onerror = function () {
      if (saveBtn) saveBtn.disabled = false;
      if (loadingIcon) loadingIcon.style.display = 'none';
      if (progressBarWrap && progressBar) {
        progressBarWrap.style.display = 'none';
        progressBar.style.width = '0%';
        progressBar.setAttribute('aria-valuenow', 0);
        progressBar.textContent = '0%';
      }
      if (typeof options.onError === 'function') options.onError(null, formEl);
      else window.ToastService.error(options.textError || 'Error saving listing.');
    };
    xhr.send(formData);
  });
}

function ListingMetaFormService(formEl) {
  if (!formEl) return;

  const submitBtn = formEl.querySelector('button[type="submit"]');
  const originalBtnHTML = submitBtn ? submitBtn.innerHTML : '';

  formEl.addEventListener('submit', async function (e) {
    e.preventDefault();

    // Validate form
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated');
      return;
    }

    // Disable button and show spinner
    if (submitBtn) {
      submitBtn.disabled = true;
      submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>';
    }

    const formData = new FormData(formEl);

    try {
      const response = await fetch(WP_API.rest_url + 'listar/v1/place/save_meta', {
        method: 'POST',
        headers: {
          'X-WP-Nonce': WP_API.nonce,
        },
        body: formData,
        credentials: 'same-origin',
      });

      const result = await response.json();

      if (response.ok && result.success) {
        window.ToastService.success(result.message || 'Meta saved successfully!');
        formEl.classList.remove('was-validated');
      } else {
        window.ToastService.error(result.message || 'Failed to save meta.');
      }
    } catch (err) {
      window.ToastService.error('Failed to save meta.');
    } finally {
      if (submitBtn) {
        submitBtn.disabled = false;
        submitBtn.innerHTML = originalBtnHTML;
      }
    }
  });
}

function BookingFormService(formEl) {
  if (!formEl) return

  const bookingStyle = formEl.dataset.bookingStyle
  const resourceId = formEl.dataset.resourceId

  const submitBtn = formEl.querySelector('#booking-submit')
  const priceResult = formEl.querySelector('#price-result')

  formEl.querySelector('[name="booking_style"]').value = bookingStyle
  formEl.querySelector('[name="resource_id"]').value = resourceId

  const fieldMap = {
    standard: [
      'booking-field-adult',
      'booking-field-children',
      'booking-field-start-date',
      'booking-field-start-time',
    ],
    daily: [
      'booking-field-adult',
      'booking-field-children',
      'booking-field-start-date',
      'booking-field-start-time',
      'booking-field-end-date',
      'booking-field-end-time',
    ],
    hourly: [
      'booking-field-adult',
      'booking-field-children',
      'booking-field-start-date',
      'booking-field-start-time',
      'booking-field-end-time',
    ],
    slot: ['booking-field-adult', 'booking-field-children'],
  }

  function toggleFields() {
    Object.values(fieldMap)
      .flat()
      .forEach((id) => {
        const el = document.getElementById(id)
        if (el) el.style.display = 'none'
      })
      ; (fieldMap[bookingStyle] || []).forEach((id) => {
        const el = document.getElementById(id)
        if (el) el.style.display = 'block'
      })
  }

  function getFormData() {
    const data = new FormData(formEl)
    const obj = {}
    data.forEach((v, k) => (obj[k] = v))
    return obj
  }

  function setLoading(state) {
    submitBtn.disabled = state
    submitBtn.querySelector('.label').style.display = state ? 'none' : ''
    submitBtn.querySelector('.loading').style.display = state ? '' : 'none'
  }

  async function estimatePrice() {
    const data = getFormData()
    setLoading(true)

    try {
      const res = await fetch(WP_API.rest_url + 'listar/v1/booking/cart', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-WP-Nonce': WP_API.nonce,
        },
        credentials: 'same-origin', // Important to send cookies
        body: JSON.stringify(data),
      })
      const json = await res.json()
      if (json.success === false) {
        window.ToastService.error(json.msg || json.message || 'Error estimating price')
      } else if (
        json.success === true &&
        json.attr &&
        json.attr.total_display
      ) {
        priceResult.innerHTML = json.attr.total_display
      }
    } catch (err) {
      window.ToastService.error('Error estimating price')
    } finally {
      setLoading(false)
    }
  }

  async function submitBooking(event) {
    event.preventDefault()
    // Check form validity
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    const data = getFormData()
    setLoading(true)

    try {
      const res = await fetch(WP_API.rest_url + 'listar/v1/booking/order', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-WP-Nonce': WP_API.nonce,
        },
        credentials: 'same-origin', // Important to send cookies
        body: JSON.stringify(data),
      })
      const json = await res.json()
      if (json.success) {
        window.ToastService.success('Booking successful!')
        formEl.reset()
        formEl.classList.remove('was-validated')
      } else {
        window.ToastService.error(json.message || 'Booking failed')
      }
    } catch (err) {
      window.ToastService.error('Booking error')
    } finally {
      setLoading(false)
    }
  }

  ;[
    'adult',
    'children',
    'start_date',
    'start_time',
    'end_date',
    'end_time',
  ].forEach((name) => {
    const el = formEl.querySelector(`[name="${name}"]`)
    if (el) el.addEventListener('change', estimatePrice)
  })

  formEl.addEventListener('submit', submitBooking)
  toggleFields()
}

function CommentFormService(formEl) {
  if (!formEl) return

  formEl.addEventListener('submit', function (e) {
    e.preventDefault()

    const submitBtn = formEl.querySelector('button[type="submit"]')
    if (!submitBtn) return
    const originalBtnText = submitBtn.innerHTML

    // Validate the form using built-in constraint validation API
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    const formData = new FormData(formEl)
    const xhr = new XMLHttpRequest()

    // Disable button and show loading spinner
    submitBtn.disabled = true
    submitBtn.innerHTML =
      '<span class="spinner-border spinner-border-sm me-2"></span>'

    xhr.open('POST', formEl.action, true)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        if (xhr.status === 200 || xhr.status === 302) {
          window.ToastService.success('Your comment has been submitted successfully!')
          formEl.classList.remove('was-validated')
          setTimeout(() => location.reload(), 2000) // Reload to show new comment
        } else {
          const errorMsg =
            window.ToastService.extractErrorMessage?.(xhr.responseText) ||
            'Submission failed.'
          window.ToastService.error(errorMsg)

          // Re-enable button and restore text
          submitBtn.disabled = false
          submitBtn.innerHTML = originalBtnText
        }
      }
    }

    xhr.send(formData)
  })
}

function ClaimFormService(formEl) {
  if (!formEl) return

  const submitBtn = formEl.querySelector('#claim-submit')
  const loadingSpan = submitBtn?.querySelector('.loading')
  const labelSpan = submitBtn?.querySelector('.label')

  formEl.addEventListener('submit', async function (e) {
    e.preventDefault()

    if (!submitBtn) return

    // Check form validity
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    submitBtn.disabled = true
    if (loadingSpan) loadingSpan.style.display = 'inline-block'
    if (labelSpan) labelSpan.style.display = 'none'

    const data = {
      id: formEl.querySelector('input[name="id"]')?.value || '',
      first_name: formEl.querySelector('input[name="first_name"]')?.value || '',
      last_name: formEl.querySelector('input[name="last_name"]')?.value || '',
      phone: formEl.querySelector('input[name="phone"]')?.value || '',
      email: formEl.querySelector('input[name="email"]')?.value || '',
      memo: formEl.querySelector('textarea[name="memo"]')?.value || '',
    }

    try {
      const res = await fetch(WP_API.rest_url + 'listar/v1/claim/submit', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-WP-Nonce': WP_API.nonce,
        },
        credentials: 'same-origin',
        body: JSON.stringify(data),
      })

      const json = await res.json()

      if (json.success) {
        window.ToastService.success('Claim submitted successfully!')
        formEl.reset()
        formEl.classList.remove('was-validated')
      } else {
        window.ToastService.error(json.message || 'Claim failed.')
      }
    } catch (err) {
      window.ToastService.error('Claim failed.')
    } finally {
      submitBtn.disabled = false
      if (loadingSpan) loadingSpan.style.display = 'none'
      if (labelSpan) labelSpan.style.display = 'inline-block'
    }
  })
}

function ContactFormService(formEl) {
  if (!formEl) return

  const submitBtn = formEl.querySelector('button[type="submit"]')
  if (!submitBtn) return

  const originalBtnHTML = submitBtn.innerHTML

  formEl.addEventListener('submit', async function (e) {
    e.preventDefault()

    // Check form validity
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    // Disable button and show spinner
    submitBtn.disabled = true
    submitBtn.innerHTML =
      '<span class="spinner-border spinner-border-sm me-2"></span>Processing...'

    const data = {
      resource_id: formEl.getAttribute('data-id'),
      name: formEl.querySelector('[name="name"]')?.value || '',
      email: formEl.querySelector('[name="email"]')?.value || '',
      phone: formEl.querySelector('[name="phone"]')?.value || '',
      message: formEl.querySelector('textarea')?.value || '',
    }

    try {
      const res = await fetch(WP_API.rest_url + 'listar/v1/author/contact', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-WP-Nonce': WP_API.nonce,
        },
        credentials: 'same-origin',
        body: JSON.stringify(data),
      })

      const json = await res.json()

      if (json.success) {
        window.ToastService.success(
          json.msg || json.message || 'Message sent successfully!'
        )
        formEl.reset()
        formEl.classList.remove('was-validated')
      } else {
        window.ToastService.error(
          json.msg || json.message || 'Message failed to send.'
        )
      }
    } catch (err) {
      window.ToastService.error('Message failed to send.')
    } finally {
      submitBtn.disabled = false
      submitBtn.innerHTML = originalBtnHTML
    }
  })
}

function ScheduleFormService(formEl) {
  if (!formEl) return

  const submitBtn = formEl.querySelector('button[type="submit"]')
  if (!submitBtn) return

  const originalBtnHTML = submitBtn.innerHTML

  formEl.addEventListener('submit', async function (e) {
    e.preventDefault()

    // Check form validity
    if (!formEl.checkValidity()) {
      formEl.classList.add('was-validated')
      return
    }

    // Disable button and show loading spinner
    submitBtn.disabled = true
    submitBtn.innerHTML =
      '<span class="spinner-border spinner-border-sm me-2"></span>Processing...'

    const data = {
      resource_id: formEl.getAttribute('data-id'),
      person: 1, // Default to 1 person
      start_date: formEl.querySelector('[name="start_date"]')?.value || '',
      start_time: formEl.querySelector('[name="start_time"]')?.value || '',
      first_name: formEl.querySelector('[name="first_name"]')?.value || '',
      last_name: formEl.querySelector('[name="last_name"]')?.value || '',
      email: formEl.querySelector('[name="email"]')?.value || '',
      phone: formEl.querySelector('[name="phone"]')?.value || '',
      memo: formEl.querySelector('[name="memo"]')?.value || '',
    }

    try {
      const res = await fetch(WP_API.rest_url + 'listar/v1/booking/order', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-WP-Nonce': WP_API.nonce,
        },
        credentials: 'same-origin',
        body: JSON.stringify(data),
      })

      const json = await res.json()

      if (json.success) {
        window.ToastService.success(json.msg || 'Booking successful!')
        formEl.reset()
        formEl.classList.remove('was-validated')
      } else {
        if (json.code && json.message) {
          // Show alert if both code and message are present
          window.ToastService.error(json.message)
        } else {
          // Fallback to ToastService error
          window.ToastService.error(json.msg || 'Booking failed.')
        }
      }
    } catch (err) {
      window.ToastService.error('Booking failed.')
    } finally {
      submitBtn.disabled = false
      submitBtn.innerHTML = originalBtnHTML
    }
  })
}

function OpenHoursFormService(formEl) {
  if (!formEl) return
  var submitBtn = formEl.querySelector('#open-hours-submit')
  var label = submitBtn ? submitBtn.querySelector('.label') : null
  var loading = submitBtn ? submitBtn.querySelector('.loading') : null
  formEl.addEventListener('submit', async function (e) {
    e.preventDefault()
    if (submitBtn) {
      submitBtn.disabled = true
      if (label) label.style.display = 'none'
      if (loading) loading.style.display = ''
    }
    var formData = new FormData(formEl)
    // Add post_id if not present
    if (!formData.has('post_id')) {
      var postId = formEl.getAttribute('data-post-id')
      if (postId) formData.append('post_id', postId)
    }
    try {
      const response = await fetch(
        WP_API.rest_url + 'listar/v1/place/schedule',
        {
          method: 'POST',
          headers: {
            'X-WP-Nonce': WP_API?.nonce || '',
          },
          body: formData,
          credentials: 'same-origin',
        }
      )
      const result = await response.json()
      if (response.ok && result.success) {
        window.ToastService.success(result.message || 'Working hours saved!')
      } else {
        window.ToastService.error(result.message || 'Failed to save working hours.')
      }
    } catch (err) {
      window.ToastService.error('Failed to save working hours.')
    } finally {
      if (submitBtn) {
        submitBtn.disabled = false
        if (label) label.style.display = ''
        if (loading) loading.style.display = 'none'
      }
    }
  })
}

// DOMContentLoaded
document.addEventListener('DOMContentLoaded', function () {
  // Form handlers
  const formHandlerMap = {
    listing: ListingFormService,
    listingMeta: ListingMetaFormService,
    booking: BookingFormService,
    comment: CommentFormService,
    claim: ClaimFormService,
    contact: ContactFormService,
    schedule: ScheduleFormService,
    openHours: OpenHoursFormService,
    filterSidebar: filterSidebarFormService, // new case
  }
  
  // Form handlers: Check all forms with data-form-handler attribute
  document
    .querySelectorAll('form[data-form-handler]')
    .forEach((form) => {
      const type = form.dataset.formHandler
      const handler = formHandlerMap[type]
      if (handler) {
        handler(form)
      }
    })

  // Pill: Button Remove
  document
    .querySelectorAll('[data-remove]')
    .forEach((button) => {
      button.addEventListener('click', () => {
        const param = button.getAttribute('data-remove')
        const valueToRemove = button.getAttribute('data-value')
        const url = new URL(window.location.href)
        const params = url.searchParams

        // Collect all values for both `param` and `param[]`
        const allValues = [
          ...params.getAll(param),
          ...params.getAll(param + '[]'),
        ]

        // Remove all existing keys
        params.delete(param)
        params.delete(param + '[]')

        // Re-add filtered values (excluding the one to remove)
        allValues
          .filter((v) => v !== valueToRemove)
          .forEach((v) => {
            params.append(param + '[]', v) // Normalize to array format
          })

        // Apply the updated URL
        url.search = params.toString()
        window.location.href = url.toString()
      })
    })

  // Comment: "Reply" buttons handling
  document
    .querySelectorAll('[data-action="reply-comment"]')
    .forEach((button) => {
      button.addEventListener('click', function (e) {
        e.preventDefault()

        // Find the comment form element dynamically
        const commentFormElm = document.querySelector(
          'form[data-form-handler="comment"]'
        )

        if (!commentFormElm) {
          console.error('Comment form not found.')
          return
        }

        // Find the input[name="comment_parent"] inside the comment form
        const commentParentInput = commentFormElm.querySelector(
          'input[name="comment_parent"]'
        )
        const parentId = this.dataset.commentId
        commentFormElm.reset()
        commentFormElm.classList.remove('was-validated')
        commentParentInput.value = parentId // 'input[name="comment_parent"]'

        // Remove rating field if it exists
        const ratingSelect = commentFormElm.querySelector(
          'select[name="rating"]'
        )

        if (ratingSelect) {
          ratingSelect.removeAttribute('name') // Prevent it from being submitted
          ratingSelect.removeAttribute('required') // Also remove required
        }

        const ratingWrapper = document.getElementById('ratingWrapper')
        if (ratingWrapper) {
          ratingWrapper.style.display = 'none'
        }

        // Reset the post if it exists data set
        const postId = this.dataset.postId
        const postIdElm = commentFormElm.querySelector(
          'input[name="comment_post_ID"]'
        )

        if (postId) {
          postIdElm.value = postId
        }

        const modal = bootstrap.Modal.getOrCreateInstance(
          document.getElementById('reviewForm')
        )
        modal.show()
      })

      return false
    })

  // Wishlist: Toggle
  document
    .querySelectorAll('[data-action="wishlist"]')
    .forEach((button) => {
      button.addEventListener('click', async function () {
        const btn = this
        const icon = btn.querySelector('i')
        const listingId = btn.getAttribute('data-id')
        const isWishlist = btn.getAttribute('data-wishlist') === '1'

        if (!listingId) return

        // Disable button and show loading spinner
        btn.disabled = true
        icon.className = 'spinner-border spinner-border-sm'

        const endpoint = isWishlist
          ? WP_API.rest_url + 'listar/v1/wishlist/remove'
          : WP_API.rest_url + 'listar/v1/wishlist/save'

        try {
          const response = await fetch(endpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-WP-Nonce': WP_API?.nonce || '',
            },
            body: JSON.stringify({ post_id: listingId }),
            credentials: 'same-origin',
          })

          const result = await response.json()

          if (response.ok && result.success) {
            if (isWishlist) {
              // Remove from wishlist
              icon.className = 'fi-heart fs-base'
              btn.classList.remove('active')
              btn.setAttribute('data-wishlist', '0')
            } else {
              // Add to wishlist
              icon.className = 'fi-heart-filled fs-base text-danger'
              btn.classList.add('active')
              btn.setAttribute('data-wishlist', '1')
            }
          } else {
            // Failed – revert icon
            icon.className = 'fi-heart fs-base'
            window.ToastService.error(result.message || 'Wishlist API error')
          }
        } catch (err) {
          window.ToastService.error('Wishlist API error:', err)
          icon.className = 'fi-heart fs-base' // Fallback
        } finally {
          btn.disabled = false
        }
      })
    })

  // Wishlist: Remove
  document
    .querySelectorAll('button[data-action="wishlist-remove"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const article = this.closest('article')
        const icon = this.querySelector('i')
        const originalIconClass = icon ? icon.className : ''
        // Replace icon with spinner
        if (icon) {
          icon.className = 'spinner-border spinner-border-sm'
        }
        this.disabled = true
        // Get post ID from article or button (try data-id, fallback to article data-id or hidden input)
        let postId = this.getAttribute('data-id')
        if (!postId && article) {
          postId = article.getAttribute('data-id')
        }

        if (!postId) {
          window.ToastService.error('No post ID found.')
          if (icon) icon.className = originalIconClass
          this.disabled = false
          return
        }
        try {
          const endpoint = WP_API.rest_url + 'listar/v1/wishlist/remove'
          const response = await fetch(endpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-WP-Nonce': WP_API?.nonce || '',
            },
            body: JSON.stringify({ post_id: postId }),
            credentials: 'same-origin',
          })
          const result = await response.json()
          if (response.ok && result.success) {
            window.ToastService.success(
              result.msg || result.message || 'Removed from wishlist.'
            )
            if (article) article.remove()
          } else {
            window.ToastService.error(
              result.msg || result.message || 'Failed to remove from wishlist.'
            )
            if (icon) icon.className = originalIconClass
            this.disabled = false
          }
        } catch (err) {
          window.ToastService.error('Failed to remove from wishlist.')
          if (icon) icon.className = originalIconClass
          this.disabled = false
        }
      })
    })

  // Booking: Cancel
  document
    .querySelectorAll('button[data-action="booking-cancel"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const bookingId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!bookingId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        try {
          const res = await fetch(
            WP_API.rest_url + 'listar/v1/booking/cancel_by_id',
            {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': WP_API.nonce,
              },
              credentials: 'same-origin',
              body: JSON.stringify({ id: bookingId }),
            }
          )
          const json = await res.json()
          if (json.success) {
            window.ToastService.success(
              json.msg || json.message || 'Booking cancelled successfully!'
            )
            window.location.reload()
          } else {
            window.ToastService.error(json.msg || json.message || 'Cancel failed.')
          }
        } catch (err) {
          window.ToastService.error('Cancel failed.')
        } finally {
          this.disabled = false
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')
        }
      })
    })

  // Booking: Pay
  document
    .querySelectorAll('button[data-action="booking-pay"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const bookingId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!bookingId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        // timeout
        setTimeout(() => {
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')

          window.ToastService.success(
            'Payment processing is not implemented yet. This is a placeholder action.'
          )
        }, 3000)
      })
    })

  // Booking: Accept
  document
    .querySelectorAll('button[data-action="booking-accept"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const bookingId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!bookingId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        try {
          const res = await fetch(
            WP_API.rest_url + 'listar/v1/booking/accept_by_id',
            {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': WP_API.nonce,
              },
              credentials: 'same-origin',
              body: JSON.stringify({ id: bookingId }),
            }
          )
          const json = await res.json()
          if (json.success) {
            window.ToastService.success(
              json.msg || json.message || 'Booking accepted successfully!'
            )
            window.location.reload()
          } else {
            window.ToastService.error(json.msg || json.message || 'Accept failed.')
          }
        } catch (err) {
          window.ToastService.error('Accept failed.')
        } finally {
          this.disabled = false
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')
        }
      })
    })

  // Claim: Cancel
  document
    .querySelectorAll('button[data-action="claim-cancel"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const claimId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!claimId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        try {
          const res = await fetch(
            WP_API.rest_url + 'listar/v1/claim/cancel_by_id',
            {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': WP_API.nonce,
              },
              credentials: 'same-origin',
              body: JSON.stringify({ id: claimId }),
            }
          )
          const json = await res.json()
          if (json.success) {
            window.ToastService.success(
              json.msg || json.message || 'Claim cancelled successfully!'
            )
            window.location.reload()
          } else {
            window.ToastService.error(json.msg || json.message || 'Cancel failed.')
          }
        } catch (err) {
          window.ToastService.error('Cancel failed.')
        } finally {
          this.disabled = false
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')
        }
      })
    })

  // Claim: Pay
  document
    .querySelectorAll('button[data-action="claim-pay"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const claimId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!claimId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        // timeout
        setTimeout(() => {
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')
          window.ToastService.success(
            'Claim payment processing is not implemented yet. This is a placeholder action.'
          )
        }, 3000)
      })
    })

  // Claim: Accept
  document
    .querySelectorAll('button[data-action="claim-accept"]')
    .forEach(function (btn) {
      btn.addEventListener('click', async function () {
        const claimId = this.getAttribute('data-id')
        const label = this.querySelector('.btn-label')
        const spinner = this.querySelector('.spinner-border')
        if (!claimId) return

        // Show loading
        this.disabled = true
        if (label) label.style.display = 'none'
        if (spinner) spinner.classList.remove('d-none')

        try {
          const res = await fetch(
            WP_API.rest_url + 'listar/v1/claim/accept_by_id',
            {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': WP_API.nonce,
              },
              credentials: 'same-origin',
              body: JSON.stringify({ id: claimId }),
            }
          )
          const json = await res.json()
          if (json.success) {
            window.ToastService.success(
              json.msg || json.message || 'Claim accepted successfully!'
            )
            window.location.reload()
          } else {
            window.ToastService.error(json.msg || json.message || 'Accept failed.')
          }
        } catch (err) {
          window.ToastService.error('Accept failed.')
        } finally {
          this.disabled = false
          if (label) label.style.display = ''
          if (spinner) spinner.classList.add('d-none')
        }
      })
    })

})
