import './style.css';

(() => {
  const toInt = (value, fallback) => {
    const parsed = Number.parseInt(String(value), 10);
    return Number.isFinite(parsed) ? parsed : fallback;
  };

  const setLastVisible = (items) => {
    items.forEach((item) => item.classList.remove('is-last-visible'));

    const lastVisible = items[items.length - 1];
    if (lastVisible) {
      lastVisible.classList.add('is-last-visible');
    }
  };

  const initRevealPagination = (widget, items, loadWrap, loadButton, mode) => {
    const step = Math.max(1, toInt(widget.dataset.postsPerPage, items.length || 1));
    const state = {
      items,
      loadWrap,
      loadButton,
      mode,
      step,
      visibleCount: mode === 'no' ? items.length : Math.min(step, items.length),
    };

    const refresh = () => {
      state.items.forEach((item, index) => {
        const isVisible = index < state.visibleCount;
        item.hidden = !isVisible;
        item.classList.toggle('is-hidden', !isVisible);
      });

      setLastVisible(state.items.filter((item) => !item.hidden));

      if (!(state.loadWrap instanceof HTMLElement)) {
        return;
      }

      const isComplete = state.visibleCount >= state.items.length;
      if (state.mode === 'no' || state.items.length <= state.step) {
        state.loadWrap.hidden = true;
        return;
      }

      state.loadWrap.hidden = isComplete;
    };

    const revealNext = () => {
      if (state.visibleCount >= state.items.length) {
        refresh();
        return;
      }

      state.visibleCount = Math.min(state.visibleCount + state.step, state.items.length);
      refresh();
    };

    if (state.mode === 'yes' && state.loadButton instanceof HTMLButtonElement) {
      state.loadButton.addEventListener('click', revealNext);
    }

    if (state.mode === 'infinity' && state.loadWrap instanceof HTMLElement) {
      const configuredOffset = toInt(widget.dataset.infinityOffset, -200);
      const bottomMargin = configuredOffset < 0 ? Math.abs(configuredOffset) : configuredOffset * -1;
      const observer = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (!entry.isIntersecting) {
              return;
            }

            revealNext();
            if (state.visibleCount >= state.items.length) {
              observer.disconnect();
            }
          });
        },
        {
          root: null,
          rootMargin: `0px 0px ${bottomMargin}px 0px`,
          threshold: 0,
        }
      );

      observer.observe(state.loadWrap);
    }

    refresh();
  };

  const initAjaxPagination = (widget, appender, items, loadWrap, loadButton, mode) => {
    if (!(loadWrap instanceof HTMLElement) || !(loadButton instanceof HTMLButtonElement)) {
      if (items.length) {
        setLastVisible(items);
      }
      return;
    }

    const ajaxUrl = String(loadButton.dataset.ajaxUrl || '');
    const nonce = String(loadButton.dataset.ajaxNonce || '');
    const widgetId = String(loadButton.dataset.widgetId || '');
    const pageId = toInt(loadButton.dataset.pageId, 0);

    if (!ajaxUrl || !nonce || !widgetId || pageId < 1) {
      setLastVisible(items);
      loadWrap.hidden = true;
      return;
    }

    let isLoading = false;
    const labelNode = loadButton.querySelector('.eael_load_more_text');
    const defaultLabel = String(loadButton.dataset.defaultLabel || '').trim();
    const loadingLabel = String(loadButton.dataset.loadingLabel || '').trim();

    const setLoadingState = (loading) => {
      isLoading = loading;
      loadButton.disabled = loading;
      loadButton.setAttribute('aria-busy', loading ? 'true' : 'false');
      loadButton.classList.toggle('button--loading', loading);

      if (labelNode) {
        labelNode.textContent = loading && loadingLabel
          ? loadingLabel
          : defaultLabel;
      }
    };

    const setCompletionState = (hasMore) => {
      loadWrap.hidden = !hasMore;

      if (!hasMore) {
        const visibleItems = Array.from(appender.querySelectorAll('.calio-post-timeline-item'));
        setLastVisible(visibleItems);
      }
    };

    const requestNextPage = async () => {
      if (isLoading) {
        return;
      }

      const currentPage = toInt(loadButton.dataset.page, 1);
      const maxPage = toInt(loadButton.dataset.maxPage, 1);
      const nextPage = currentPage + 1;

      if (nextPage > maxPage) {
        setCompletionState(false);
        return;
      }

      setLoadingState(true);

      try {
        const formData = new FormData();
        formData.append('action', 'calio_post_timeline_load_more');
        formData.append('_ajax_nonce', nonce);
        formData.append('page_id', String(pageId));
        formData.append('widget_id', widgetId);
        formData.append('page', String(nextPage));

        const response = await fetch(ajaxUrl, {
          method: 'POST',
          credentials: 'same-origin',
          body: formData,
        });

        const result = await response.json();
        if (!result || result.success !== true) {
          throw new Error(result?.data?.message || 'Unknown load more error.');
        }

        const payload = result.data || {};
        const html = typeof payload.html === 'string' ? payload.html.trim() : '';
        const resolvedPage = toInt(payload.page, nextPage);
        const resolvedMaxPage = toInt(payload.max_page, maxPage);
        const hasMore = Boolean(payload.has_more);

        loadButton.dataset.page = String(resolvedPage);
        loadButton.dataset.maxPage = String(Math.max(1, resolvedMaxPage));

        if (html) {
          appender.insertAdjacentHTML('beforeend', html);
        }

        setCompletionState(hasMore && html !== '');
      } catch (error) {
        // Keep the button available so the user can retry.
        // eslint-disable-next-line no-console
        console.error('Calio Post Timeline load more failed.', error);
      } finally {
        setLoadingState(false);
      }
    };

    if (mode === 'yes') {
      loadButton.addEventListener('click', (event) => {
        event.preventDefault();
        requestNextPage();
      });
    }

    if (mode === 'infinity') {
      const configuredOffset = toInt(loadWrap.dataset.offset, -200);
      const bottomMargin = configuredOffset < 0 ? Math.abs(configuredOffset) : configuredOffset * -1;
      const observer = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              requestNextPage();
            }
          });
        },
        {
          root: null,
          rootMargin: `0px 0px ${bottomMargin}px 0px`,
          threshold: 0,
        }
      );

      observer.observe(loadWrap);
    }
  };

  const initWidget = (widget) => {
    if (!(widget instanceof HTMLElement) || widget.dataset.timelineReady === 'yes') {
      return;
    }

    const appender = widget.querySelector('.eael-post-appender');
    const items = Array.from(widget.querySelectorAll('.calio-post-timeline-item'));
    if (!(appender instanceof HTMLElement) || !items.length) {
      return;
    }

    widget.dataset.timelineReady = 'yes';

    const loadWrap = widget.querySelector('.eael-load-more-button-wrap');
    const loadButton = loadWrap ? loadWrap.querySelector('.eael-load-more-button') : null;
    const mode = String(widget.dataset.loadMode || 'no').toLowerCase();
    const paginationMode = String(widget.dataset.paginationMode || 'none').toLowerCase();

    if (paginationMode === 'reveal') {
      initRevealPagination(widget, items, loadWrap, loadButton, mode);
      return;
    }

    if (paginationMode === 'ajax') {
      initAjaxPagination(widget, appender, items, loadWrap, loadButton, mode);
      return;
    }

    setLastVisible(items);
    if (loadWrap instanceof HTMLElement) {
      loadWrap.hidden = true;
    }
  };

  const initScope = (scope) => {
    const root = scope instanceof HTMLElement
      ? scope
      : scope && scope[0] instanceof HTMLElement
        ? scope[0]
        : document;

    if (root instanceof HTMLElement && root.matches('.calio-post-timeline-widget')) {
      initWidget(root);
      return;
    }

    root.querySelectorAll('.calio-post-timeline-widget').forEach(initWidget);
  };

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

  let hookBound = false;
  const bindElementorTimeline = () => {
    if (hookBound) {
      return true;
    }

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

    window.elementorFrontend.hooks.addAction('frontend/element_ready/calio-post-timeline.default', initScope);
    hookBound = true;
    return true;
  };

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