/* ============================================================
   Tab Switch — replica of Framer Marketplace "Swtich on hover tabs"
   (Suraj Kale). Vanilla JS, no dependencies.

     new TabSwitch(el, { items: [{ title, body, shot }], index: 0 })

   All the motion is CSS; this only moves the is-active class and keeps
   the keyboard in sync. Hover is the reference's only trigger, which
   leaves it unusable by keyboard and touch - both are added here and
   can be turned off to match the original exactly.
   ============================================================ */

class TabSwitch {
  static defaults = {
    index: 0,
    trigger: 'hover',   // 'hover' | 'click' | 'both'
    keyboard: true,     // arrow-key roving tabindex (the reference has none)
    sticky: true,       // stay on the last hovered item after mouseout
  };

  constructor(root, options = {}) {
    this.root = typeof root === 'string' ? document.querySelector(root) : root;
    this.opts = { ...TabSwitch.defaults, ...options };

    if (options.items) this.#render(options.items);

    this.items = [...this.root.querySelectorAll('.tabswitch__item')];
    this.shots = [...this.root.querySelectorAll('.tabswitch__shot')];
    this.index = -1;

    this.items.forEach((item, i) => {
      if (this.opts.trigger !== 'click') {
        item.addEventListener('pointerenter', (e) => {
          if (e.pointerType === 'touch') return;   // touch fires enter+click
          this.select(i);
        });
      }
      // Click is bound once, whatever the trigger is: it is both the
      // 'click'/'both' trigger and the only way in on touch.
      item.addEventListener('click', () => this.select(i));
      item.addEventListener('focus', () => this.select(i));
      if (this.opts.keyboard) item.addEventListener('keydown', (e) => this.#key(e, i));
    });

    if (!this.opts.sticky) {
      this.root.addEventListener('pointerleave', () => this.select(this.opts.index));
    }

    this.select(this.opts.index);
  }

  select(i) {
    if (i === this.index || !this.items[i]) return;
    this.index = i;
    this.items.forEach((el, n) => {
      const on = n === i;
      el.classList.toggle('is-active', on);
      el.setAttribute('aria-selected', String(on));
      el.tabIndex = on ? 0 : -1;
    });
    this.shots.forEach((el, n) => el.classList.toggle('is-active', n === i));
    this.root.dispatchEvent(new CustomEvent('tabswitch:change', { detail: { index: i } }));
  }

  #key(e, i) {
    const last = this.items.length - 1;
    const to = { ArrowDown: i + 1, ArrowRight: i + 1, ArrowUp: i - 1, ArrowLeft: i - 1, Home: 0, End: last }[e.key];
    if (to === undefined) return;
    e.preventDefault();
    const n = Math.max(0, Math.min(last, to));
    this.select(n);
    this.items[n].focus();
  }

  #render(items) {
    const img = (s) => (typeof s === 'string' && /^(https?:|\.|\/|data:)/.test(s)
      ? `<img class="tabswitch__shot" src="${s}" alt="">`
      : `<div class="tabswitch__shot">${s ?? ''}</div>`);
    this.root.innerHTML = `
      <div class="tabswitch__rail" role="tablist" aria-orientation="vertical">
        ${items.map((it) => `
          <button class="tabswitch__item" type="button" role="tab" aria-selected="false" tabindex="-1">
            <h3 class="tabswitch__title">${it.title}</h3>
            <div class="tabswitch__reveal"><div>
              <p class="tabswitch__desc">${it.body}</p>
            </div></div>
          </button>`).join('')}
      </div>
      <div class="tabswitch__panel">
        <div class="tabswitch__stack">${items.map((it) => img(it.shot)).join('')}</div>
      </div>`;
  }
}

if (typeof module !== 'undefined') module.exports = TabSwitch;
