import './style.css';

const isAndroidDevice = () => /Android/i.test(window.navigator.userAgent || '');
const isIosDevice = () => /iPhone|iPad|iPod/i.test(window.navigator.userAgent || '');
const isTabletViewport = () => {
  const width = window.innerWidth || document.documentElement.clientWidth || 0;
  return width > 767 && width <= 1024;
};
const isDesktopViewport = () => {
  const width = window.innerWidth || document.documentElement.clientWidth || 0;
  return width > 1024;
};
const findOverflowParent = (element) => {
  let current = element.parentElement;

  while (current && current !== document.body) {
    const styles = window.getComputedStyle(current);
    const overflowValues = `${styles.overflow} ${styles.overflowX} ${styles.overflowY}`;

    if (/(auto|scroll|hidden|clip)/i.test(overflowValues)) {
      return current;
    }

    current = current.parentElement;
  }

  return null;
};
const safeQuerySelector = (selector) => {
  if (!selector) {
    return null;
  }

  try {
    return document.querySelector(selector);
  } catch (error) {
    return null;
  }
};
const findBoundaryElement = (element, selector) => {
  if (!selector) {
    return element.parentElement || element;
  }

  let current = element.parentElement;

  while (current && current !== document.body) {
    try {
      if (current.matches(selector)) {
        return current;
      }
    } catch (error) {
      break;
    }

    current = current.parentElement;
  }

  return safeQuerySelector(selector) || element.parentElement || element;
};

const initStickyContent = (element) => {
  if (!element || element.dataset.calioStickyInit === 'yes') {
    return;
  }

  element.dataset.calioStickyInit = 'yes';

  const isEditMode = typeof window.elementorFrontend?.isEditMode === 'function'
    ? window.elementorFrontend.isEditMode()
    : document.body.classList.contains('elementor-editor-active');

  if (isEditMode) {
    return;
  }

  const allowAndroid = element.dataset.calioStickyAndroid === 'yes';
  const allowIos = element.dataset.calioStickyIos === 'yes';
  const allowTablet = element.dataset.calioStickyTablet === 'yes';
  const allowDesktop = element.dataset.calioStickyDesktop !== 'no';

  const blockedByDevice = (isAndroidDevice() && !allowAndroid)
    || (isIosDevice() && !allowIos)
    || (isTabletViewport() && !allowTablet)
    || (isDesktopViewport() && !allowDesktop);

  if (blockedByDevice) {
    return;
  }

  const top = Number.parseInt(element.dataset.calioStickyTop || '24', 10) || 24;
  const zIndex = Number.parseInt(element.dataset.calioStickyZ || '5', 10) || 5;
  const widthMode = element.dataset.calioStickyWidth || 'natural';
  const shadowEnabled = element.dataset.calioStickyShadow === 'yes';
  const activeStateEnabled = element.dataset.calioStickyActiveState !== 'no';
  const overflowSafeEnabled = element.dataset.calioStickyOverflowSafe !== 'no';
  const boundarySelector = element.dataset.calioStickyBoundary || '';
  const stopBeforeSelector = element.dataset.calioStickyStopBefore || '';
  const overflowParent = findOverflowParent(element);
  const boundaryElement = findBoundaryElement(element, boundarySelector);
  const stopBeforeElement = safeQuerySelector(stopBeforeSelector);

  if (overflowParent && overflowSafeEnabled) {
    element.classList.add('calio-sticky-content-host', 'is-sticky-blocked');
    return;
  }

  element.classList.add('calio-sticky-content-host');
  if (shadowEnabled) {
    element.classList.add('has-sticky-shadow');
  }
  if (activeStateEnabled) {
    element.classList.add('has-sticky-active-state');
  }

  element.style.position = 'sticky';
  element.style.top = `${top}px`;
  element.style.zIndex = String(zIndex);

  if (widthMode === 'natural') {
    element.style.width = 'fit-content';
    element.style.maxWidth = '100%';
  }

  if (!activeStateEnabled) {
    return;
  }

  let ticking = false;

  const updateStickyState = () => {
    const rect = element.getBoundingClientRect();
    const boundaryRect = (boundaryElement || element).getBoundingClientRect();
    const stopRect = stopBeforeElement?.getBoundingClientRect() || null;
    const stopOffset = stopRect ? stopRect.top - rect.height : Number.POSITIVE_INFINITY;
    const constrainedTop = stopRect
      ? Math.min(top, stopOffset)
      : top;
    const appliedTop = Math.round(constrainedTop);
    const isStopped = stopRect ? stopRect.top <= top + rect.height : false;
    const isActive = rect.top <= top + 1 && boundaryRect.bottom > rect.height + top;

    element.style.top = `${appliedTop}px`;
    element.classList.toggle('is-sticky-active', isActive);
    element.classList.toggle('is-sticky-stopped', isStopped);
    ticking = false;
  };

  const requestStickyState = () => {
    if (ticking) {
      return;
    }

    ticking = true;
    window.requestAnimationFrame(updateStickyState);
  };

  updateStickyState();
  window.addEventListener('scroll', requestStickyState, { passive: true });
  window.addEventListener('resize', requestStickyState);
};

const initAllStickyContent = (scope = document) => {
  const hosts = scope.matches?.('[data-calio-sticky-content="yes"]')
    ? [scope]
    : Array.from(scope.querySelectorAll('[data-calio-sticky-content="yes"]'));

  hosts.forEach(initStickyContent);
};

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

let calioStickyContentHookBound = false;
const bindElementorStickyContent = () => {
  if (calioStickyContentHookBound) {
    return true;
  }

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

  window.elementorFrontend.hooks.addAction('frontend/element_ready/global', ($scope) => {
    const root = $scope?.[0] || null;
    if (root) {
      initAllStickyContent(root);
    }
  });

  calioStickyContentHookBound = true;
  return true;
};

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