import { useEffect } from 'react';

const TRIGGER_THRESHOLD = 120;
const SHOW_INDICATOR_THRESHOLD = 60;

const MAX = 128;
const k = 0.4;
function appr(x: number) {
  return MAX * (1 - Math.exp((-k * x) / MAX));
}

export const usePullToRefresh = (ref: React.RefObject<HTMLDivElement>, onTrigger: () => void) => {
  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    el.addEventListener('touchstart', handleTouchStart, { passive: true });

    function handleTouchStart(startEvent: TouchEvent) {
      const el = ref.current;
      if (!el) return;

      const initialY = startEvent.touches[0]!.clientY;

      el.addEventListener('touchmove', handleTouchMove, { passive: false });
      el.addEventListener('touchend', handleTouchEnd);

      function handleTouchMove(moveEvent: TouchEvent) {
        const el = ref.current;
        if (!el) return;

        const currentY = moveEvent.touches[0]!.clientY;
        const dy = currentY - initialY;

        if (dy < 0) return;
        const parentEl = el.parentNode as HTMLDivElement;
        if (dy > TRIGGER_THRESHOLD) {
          flipArrow(parentEl);
        } else if (dy > SHOW_INDICATOR_THRESHOLD) {
          addPullIndicator(parentEl);
        } else {
          removePullIndicator(parentEl);
        }

        el.style.transform = `translateY(${appr(dy)}px)`;
      }

      function addPullIndicator(el: HTMLDivElement) {
        const indicator = el.querySelector('.pull-indicator');
        if (indicator) {
          if (indicator.classList.contains('flip')) {
            indicator.classList.remove('flip');
          }
          return;
        }

        const pullIndicator = document.createElement('div');
        pullIndicator.className = 'pull-indicator text-gray-500';
        pullIndicator.innerHTML = `
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 19c-.3 0-.6-.1-.8-.3l-6-6c-.4-.4-.4-1 0-1.4s1-.4 1.4 0L11 16.2V5c0-.6.4-1 1-1s1 .4 1 1v11.2l4.4-4.4c.4-.4 1-.4 1.4 0s.4 1 0 1.4l-6 6c-.2.2-.5.3-.8.3z"/>
          </svg>
        `;
        el.appendChild(pullIndicator);
      }

      function removePullIndicator(el: HTMLDivElement) {
        const pullIndicator = el.querySelector('.pull-indicator');
        if (pullIndicator) {
          pullIndicator.remove();
        }
      }

      function flipArrow(el: HTMLDivElement) {
        const pullIndicator = el.querySelector('.pull-indicator');
        if (pullIndicator && !pullIndicator.classList.contains('flip')) {
          pullIndicator.classList.add('flip');
        }
      }

      function handleTouchEnd(endEvent: TouchEvent) {
        const el = ref.current;
        if (!el) return;

        el.style.transform = 'translateY(0)';
        removePullIndicator(el.parentNode as HTMLDivElement);

        el.style.transition = 'transform 0.2s';

        const y = endEvent.changedTouches[0]!.clientY;
        const dy = y - initialY;
        if (dy > TRIGGER_THRESHOLD) {
          onTrigger();
        }

        el.addEventListener('transitionend', onTransitionEnd);

        el.removeEventListener('touchmove', handleTouchMove);
        el.removeEventListener('touchend', handleTouchEnd);
      }

      function onTransitionEnd() {
        const el = ref.current;
        if (!el) return;

        el.style.transition = '';
        el.removeEventListener('transitionend', onTransitionEnd);
      }
    }

    return () => {
      el.removeEventListener('touchstart', handleTouchStart);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ref.current]);
};
