import './style.css';

/**
 * Handles lightweight category filtering for the Filterable Gallery widget.
 */
const initFilterableGallery = (widget) => {
  if (widget.dataset.calioFilterableGalleryInit === 'yes') {
    return;
  }

  widget.dataset.calioFilterableGalleryInit = 'yes';

  const buttons = Array.from(widget.querySelectorAll('.calio-filterable-gallery-filter'));
  const items = Array.from(widget.querySelectorAll('.calio-filterable-gallery-item'));
  const emptyState = widget.querySelector('.calio-filterable-gallery-empty-state');
  const status = widget.querySelector('.calio-filterable-gallery-status');
  const badges = widget.querySelector('.calio-filterable-gallery-badges');
  const loadMoreButton = widget.querySelector('.calio-filterable-gallery-load-more');
  const searchInput = widget.querySelector('.calio-filterable-gallery-search-input');
  const resetButton = widget.querySelector('.calio-filterable-gallery-reset');
  const grid = widget.querySelector('.calio-filterable-gallery-grid');
  const enableLoadMore = widget.dataset.loadMore === 'yes';
  const useShuffleMotion = widget.classList.contains('filter-motion-shuffle');
  const sortMode = widget.dataset.sortMode || 'none';
  const initialItems = Number.parseInt(widget.dataset.initialItems || '6', 10) || 6;
  const loadMoreCount = Number.parseInt(widget.dataset.loadMoreCount || '3', 10) || 3;
  const allLoadedText = widget.dataset.allLoadedText || 'All items loaded';
  let currentFilter = 'all';
  let currentSearch = '';
  let visibleLimit = initialItems;

  if (items.length === 0) {
    return;
  }

  const syncButtons = (filter) => {
    buttons.forEach((button) => {
      const isActive = button.dataset.filter === filter;
      button.classList.toggle('is-active', isActive);
      button.setAttribute('aria-selected', isActive ? 'true' : 'false');
    });
  };

  const sortItems = (collection) => {
    const sorted = [...collection];

    if (sortMode === 'title-asc') {
      sorted.sort((left, right) => (left.dataset.sortTitle || '').localeCompare(right.dataset.sortTitle || ''));
    } else if (sortMode === 'title-desc') {
      sorted.sort((left, right) => (right.dataset.sortTitle || '').localeCompare(left.dataset.sortTitle || ''));
    } else if (sortMode === 'category') {
      sorted.sort((left, right) => {
        const categoryDiff = (left.dataset.sortCategory || '').localeCompare(right.dataset.sortCategory || '');

        if (categoryDiff !== 0) {
          return categoryDiff;
        }

        return (left.dataset.sortTitle || '').localeCompare(right.dataset.sortTitle || '');
      });
    }

    return sorted;
  };

  const matchingItems = (filter) => items.filter((item) => {
    const groups = (item.dataset.filterGroups || '')
      .split(',')
      .map((group) => group.trim())
      .filter(Boolean);
    const searchText = (item.dataset.searchText || '').toLowerCase();
    const matchesSearch = currentSearch === '' || searchText.includes(currentSearch);

    return (filter === 'all' || groups.includes(filter)) && matchesSearch;
  });

  const revealItem = (item) => {
    window.clearTimeout(Number(item.dataset.hideTimer || '0'));
    item.hidden = false;
    window.requestAnimationFrame(() => {
      item.classList.remove('is-hidden');
      item.classList.add('is-visible');
    });
  };

  const hideItem = (item) => {
    window.clearTimeout(Number(item.dataset.hideTimer || '0'));
    item.classList.remove('is-visible');
    item.classList.add('is-hidden');
    item.dataset.hideTimer = String(window.setTimeout(() => {
      item.hidden = true;
    }, 180));
  };

  const updateStatus = (visibleCount, totalCount) => {
    if (!status) {
      return;
    }

    if (totalCount === 0) {
      status.textContent = '0 items';
      return;
    }

    if (enableLoadMore) {
      if (visibleCount >= totalCount) {
        status.textContent = allLoadedText;
        return;
      }

      status.textContent = `${visibleCount} / ${totalCount} items`;
      return;
    }

    status.textContent = `${totalCount} items`;
  };

  const updateBadges = () => {
    if (!badges) {
      return;
    }

    const parts = [];
    const activeButton = buttons.find((button) => button.dataset.filter === currentFilter);
    const activeLabel = activeButton?.querySelector('span')?.textContent?.trim() || '';

    if (currentFilter !== 'all' && activeLabel !== '') {
      parts.push(`Filter: ${activeLabel}`);
    }

    if (currentSearch !== '') {
      parts.push(`Search: ${currentSearch}`);
    }

    badges.replaceChildren();
    parts.forEach((part) => {
      const badge = document.createElement('span');
      badge.className = 'calio-filterable-gallery-badge';
      badge.textContent = part;
      badges.appendChild(badge);
    });
    badges.hidden = parts.length === 0;
  };

  const updateLoadMoreButton = (visibleCount, totalCount) => {
    if (!loadMoreButton) {
      return;
    }

    const hasMore = enableLoadMore && totalCount > visibleCount;
    loadMoreButton.hidden = !hasMore;
    loadMoreButton.disabled = !hasMore;
  };

  const render = () => {
    const filteredItems = sortItems(matchingItems(currentFilter));
    const visibleItems = enableLoadMore
      ? filteredItems.slice(0, visibleLimit)
      : filteredItems;
    const visibleSet = new Set(visibleItems);
    const orderedItems = [...filteredItems, ...sortItems(items.filter((item) => !filteredItems.includes(item)))];

    syncButtons(currentFilter);
    updateBadges();

    if (grid && useShuffleMotion) {
      orderedItems.forEach((item, index) => {
        item.style.setProperty('--calio-filter-stagger', String(index));
        grid.appendChild(item);
      });
      grid.classList.remove('is-shuffling');
      window.requestAnimationFrame(() => {
        grid.classList.add('is-shuffling');
      });
    } else {
      visibleItems.forEach((item, index) => {
        item.style.setProperty('--calio-filter-stagger', String(index));
      });
    }

    items.forEach((item) => {
      if (visibleSet.has(item)) {
        revealItem(item);
      } else {
        hideItem(item);
      }
    });

    if (emptyState) {
      emptyState.hidden = filteredItems.length > 0;
    }

    widget.classList.toggle('has-no-results', filteredItems.length === 0);
    updateStatus(visibleItems.length, filteredItems.length);
    updateLoadMoreButton(visibleItems.length, filteredItems.length);
  };

  const applyFilter = (filter) => {
    currentFilter = filter;
    visibleLimit = initialItems;
    render();
  };

  buttons.forEach((button) => {
    button.addEventListener('click', () => {
      applyFilter(button.dataset.filter || 'all');
    });
  });

  if (searchInput) {
    searchInput.addEventListener('input', () => {
      currentSearch = searchInput.value.trim().toLowerCase();
      visibleLimit = initialItems;
      render();
    });
  }

  if (loadMoreButton) {
    loadMoreButton.addEventListener('click', () => {
      visibleLimit += loadMoreCount;
      render();
    });
  }

  if (resetButton) {
    resetButton.addEventListener('click', () => {
      currentFilter = 'all';
      currentSearch = '';
      visibleLimit = initialItems;

      if (searchInput) {
        searchInput.value = '';
      }

      render();
    });
  }

  applyFilter('all');
};

const initAllFilterableGalleries = (scope = document) => {
  scope.querySelectorAll('.calio-filterable-gallery').forEach(initFilterableGallery);
};

document.addEventListener('DOMContentLoaded', () => {
  initAllFilterableGalleries(document);
});

let calioFilterableGalleryHookBound = false;
const bindElementorFilterableGallery = () => {
  if (calioFilterableGalleryHookBound) {
    return true;
  }

  if (!window.elementorFrontend?.hooks) {
    return false;
  }

  window.elementorFrontend.hooks.addAction('frontend/element_ready/calio-filterable-gallery.default', ($scope) => {
    const root = $scope?.[0] || null;
    if (root) {
      initAllFilterableGalleries(root);
    }
  });

  calioFilterableGalleryHookBound = true;
  return true;
};

window.addEventListener('elementor/frontend/init', bindElementorFilterableGallery);
if (!bindElementorFilterableGallery()) {
  let attempts = 0;
  const timer = window.setInterval(() => {
    attempts += 1;
    if (bindElementorFilterableGallery() || attempts >= 40) {
      window.clearInterval(timer);
    }
  }, 250);
}
