/**
 * Focus-trap + body-scroll-lock utilities for modal-style overlays
 * (filter drawer, detail drawer, dialogs).
 *
 * Usage:
 *   const trap = createFocusTrap(panelEl);
 *   trap.activate(triggerEl);   // remembers trigger for focus-return
 *   trap.deactivate();          // restores focus to trigger
 *
 *   const lock = createScrollLock();
 *   lock.lock();
 *   lock.unlock();
 */

const FOCUSABLE_SELECTORS = [
  'a[href]',
  'area[href]',
  'input:not([type="hidden"]):not([disabled])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  'button:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',');

const getFocusable = (panel) => {
  if (!(panel instanceof HTMLElement)) {
    return [];
  }
  return Array.from(panel.querySelectorAll(FOCUSABLE_SELECTORS)).filter((el) => {
    if (el.getAttribute('aria-hidden') === 'true') {
      return false;
    }
    if (el instanceof HTMLElement && el.hidden) {
      return false;
    }
    return true;
  });
};

export function createFocusTrap(panel) {
  if (!(panel instanceof HTMLElement)) {
    return {
      activate() {},
      deactivate() {},
      focusFirst() {},
    };
  }

  if (!panel.hasAttribute('tabindex')) {
    panel.setAttribute('tabindex', '-1');
  }

  let active = false;
  let lastTrigger = null;

  const focusFirst = () => {
    const target = getFocusable(panel)[0] || panel;
    if (target && typeof target.focus === 'function') {
      target.focus();
    }
  };

  const onKeyDown = (event) => {
    if (!active) {
      return;
    }
    if (event.key !== 'Tab') {
      return;
    }
    const focusable = getFocusable(panel);
    if (!focusable.length) {
      event.preventDefault();
      panel.focus();
      return;
    }
    const first = focusable[0];
    const last = focusable[focusable.length - 1];
    const current = document.activeElement;
    if (event.shiftKey) {
      if (current === first || !panel.contains(current)) {
        event.preventDefault();
        last.focus();
      }
      return;
    }
    if (current === last) {
      event.preventDefault();
      first.focus();
    }
  };

  document.addEventListener('keydown', onKeyDown);

  return {
    activate(trigger = null) {
      if (active) { return; }
      active = true;
      lastTrigger = trigger && typeof trigger.focus === 'function'
        ? trigger
        : (document.activeElement instanceof HTMLElement ? document.activeElement : null);
      requestAnimationFrame(() => focusFirst());
    },
    deactivate() {
      if (!active) { return; }
      active = false;
      if (lastTrigger && typeof lastTrigger.focus === 'function' && document.contains(lastTrigger)) {
        lastTrigger.focus();
      }
      lastTrigger = null;
    },
    focusFirst,
    destroy() {
      active = false;
      lastTrigger = null;
      document.removeEventListener('keydown', onKeyDown);
    },
  };
}

/**
 * Body scroll-lock with position:fixed strategy. Reference-counted so multiple
 * overlays cooperate: the lock is only released when the last caller unlocks.
 */
const SCROLL_LOCK_ATTR = 'data-app-scroll-lock-count';

export function createScrollLock() {
  let locked = false;

  return {
    lock() {
      if (locked) { return; }
      locked = true;
      const body = document.body;
      if (!body) { return; }
      const current = Number(body.getAttribute(SCROLL_LOCK_ATTR) || '0') || 0;
      const next = current + 1;
      body.setAttribute(SCROLL_LOCK_ATTR, String(next));
      if (current === 0) {
        const y = window.scrollY || window.pageYOffset || 0;
        body.dataset.appScrollLockY = String(y);
        body.style.position = 'fixed';
        body.style.top = `-${y}px`;
        body.style.left = '0';
        body.style.right = '0';
        body.style.width = '100%';
      }
    },
    unlock() {
      if (!locked) { return; }
      locked = false;
      const body = document.body;
      if (!body) { return; }
      const current = Number(body.getAttribute(SCROLL_LOCK_ATTR) || '0') || 0;
      const next = Math.max(0, current - 1);
      if (next === 0) {
        body.removeAttribute(SCROLL_LOCK_ATTR);
        const y = Number(body.dataset.appScrollLockY || '0') || 0;
        body.style.position = '';
        body.style.top = '';
        body.style.left = '';
        body.style.right = '';
        body.style.width = '';
        delete body.dataset.appScrollLockY;
        window.scrollTo(0, y);
      } else {
        body.setAttribute(SCROLL_LOCK_ATTR, String(next));
      }
    },
  };
}
