/**
 * Non-side-effect class export for `<tabs-ui>`.
 *
 * Importing this file gives you the class(es) without auto-registering the tag.
 * Useful for test isolation, subclassing with tag-name override, or selective
 * composition.
 *
 * The auto-register path stays at `@adia-ai/web-components/components/tabs`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * <tabs-ui value="tab1">
 *   <tab-ui value="tab1" text="Tab 1">Content for tab 1</tab-ui>
 *   <tab-ui value="tab2" text="Tab 2">Content for tab 2</tab-ui>
 * </tabs-ui>
 *
 * Tabbed panel switcher. Renders a button strip from child tab-ui elements.
 * Only the active tab's content is visible.
 *
 * Events:
 *   change — { detail: { value } }
 *
 * Keyboard:
 *   ArrowLeft / ArrowRight to navigate tabs
 */

import { UIElement, html } from '../../core/element.js';
import './tab.js';

export class UITabs extends UIElement {
  static properties = {
    value:       { type: String, default: '', reflect: true },
    orientation: { type: String, default: '', reflect: true },
  };

  static template = () => null;

  #strip = null;
  #indicator = null;
  #transitionRaf = null;

  connected() {
    this.setAttribute('role', 'tablist');

    this.addEventListener('click', this.#handleClick);
    this.addEventListener('keydown', this.#handleKeydown);

    // Default to first tab if no value
    if (!this.value) {
      const first = this.querySelector('tab-ui:not([disabled])');
      if (first) this.value = first.value || first.getAttribute('value') || '';
    }
  }

  disconnected() {
    if (this.#transitionRaf != null) {
      cancelAnimationFrame(this.#transitionRaf);
      this.#transitionRaf = null;
    }
    this.removeEventListener('click', this.#handleClick);
    this.removeEventListener('keydown', this.#handleKeydown);
    this.#strip = null;
    this.#indicator = null;
  }

  get #tabs() {
    return [...this.querySelectorAll('tab-ui')];
  }

  get #enabledTabs() {
    return this.#tabs.filter(t => !t.disabled);
  }

  render() {
    const tabs = this.#tabs;
    if (!tabs.length) return;

    // Ensure button strip exists
    if (!this.#strip) {
      this.#strip = document.createElement('div');
      this.#strip.setAttribute('slot', 'strip');
      this.#strip.setAttribute('role', 'presentation');
    }
    if (this.#strip.parentElement !== this) {
      this.prepend(this.#strip);
    }

    // Reconcile buttons in the strip
    this.reconcile(
      this.#strip,
      tabs,
      (tab) => tab.value || tab.getAttribute('value') || '',
      (tab, i, existing) => {
        const val = tab.value || tab.getAttribute('value') || '';
        const text = tab.text || tab.getAttribute('text') || '';
        const icon = tab.icon || tab.getAttribute('icon') || '';
        const isActive = val === this.value;
        const isDisabled = tab.disabled || tab.hasAttribute('disabled');

        if (existing) {
          existing.textContent = '';
          if (icon) {
            const iconEl = document.createElement('icon-ui');
            iconEl.setAttribute('name', icon);
            existing.appendChild(iconEl);
          }
          if (text) {
            existing.appendChild(document.createTextNode(text));
          }
          existing.setAttribute('aria-selected', String(isActive));
          existing.setAttribute('tabindex', isActive ? '0' : '-1');
          if (isDisabled) existing.setAttribute('disabled', '');
          else existing.removeAttribute('disabled');
          if (isActive) existing.setAttribute('data-active', '');
          else existing.removeAttribute('data-active');
          existing.dataset.value = val;
          return existing;
        }

        const btn = document.createElement('div');
        btn.setAttribute('role', 'tab');
        btn.setAttribute('slot', 'tab-button');
        btn.dataset.value = val;
        btn.setAttribute('aria-selected', String(isActive));
        btn.setAttribute('tabindex', isActive ? '0' : '-1');
        if (isDisabled) btn.setAttribute('disabled', '');
        if (isActive) btn.setAttribute('data-active', '');
        if (icon) {
          const iconEl = document.createElement('icon-ui');
          iconEl.setAttribute('name', icon);
          btn.appendChild(iconEl);
        }
        if (text) {
          btn.appendChild(document.createTextNode(text));
        }
        return btn;
      },
    );

    // Update sliding indicator
    this.#updateIndicator();

    // Sync tab content visibility
    for (const tab of tabs) {
      const tabVal = tab.value || tab.getAttribute('value') || '';
      const isActive = tabVal === this.value;
      if (isActive) {
        tab.removeAttribute('hidden');
        tab.setAttribute('role', 'tabpanel');
      } else {
        tab.setAttribute('hidden', '');
      }
    }
  }

  #updateIndicator() {
    const activeBtn = this.#strip?.querySelector('[slot="tab-button"][data-active]');
    if (!activeBtn) {
      if (this.#indicator) this.#indicator.style.opacity = '0';
      return;
    }

    // Lazy-create indicator
    const isNew = !this.#indicator;
    if (isNew) {
      this.#indicator = document.createElement('span');
      this.#indicator.setAttribute('slot', 'indicator');
      this.#strip.appendChild(this.#indicator);
    }

    const stripRect = this.#strip.getBoundingClientRect();
    const btnRect = activeBtn.getBoundingClientRect();
    const isVertical = this.orientation === 'vertical';

    const apply = () => {
      if (isVertical) {
        const top = btnRect.top - stripRect.top;
        this.#indicator.style.transform = `translateY(${top}px)`;
        this.#indicator.style.height = `${btnRect.height}px`;
        this.#indicator.style.width = '';
      } else {
        const left = btnRect.left - stripRect.left;
        this.#indicator.style.transform = `translateX(${left}px)`;
        this.#indicator.style.width = `${btnRect.width}px`;
        this.#indicator.style.height = '';
      }
      this.#indicator.style.opacity = '1';
    };

    if (isNew) {
      this.#indicator.style.transition = 'none';
      apply();
      this.#transitionRaf = requestAnimationFrame(() => {
        this.#transitionRaf = null;
        if (this.#indicator) this.#indicator.style.transition = '';
      });
    } else {
      apply();
    }
  }

  #select(value) {
    if (value === this.value) return;
    this.value = value;
    this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
  }

  #handleClick = (e) => {
    const btn = e.target.closest('[slot="tab-button"]');
    if (!btn || !this.contains(btn) || btn.hasAttribute('disabled')) return;
    this.#select(btn.dataset.value);
  };

  #handleKeydown = (e) => {
    const btn = e.target.closest('[slot="tab-button"]');
    if (!btn || !this.contains(btn)) return;

    const buttons = [...this.#strip.querySelectorAll('[slot="tab-button"]:not([disabled])')];
    const idx = buttons.indexOf(btn);
    if (idx < 0) return;

    const isVertical = this.orientation === 'vertical';
    const nextKey = isVertical ? 'ArrowDown' : 'ArrowRight';
    const prevKey = isVertical ? 'ArrowUp' : 'ArrowLeft';

    let next;
    switch (e.key) {
      case nextKey: next = idx < buttons.length - 1 ? idx + 1 : 0; break;
      case prevKey: next = idx > 0 ? idx - 1 : buttons.length - 1; break;
      case 'Home':  next = 0; break;
      case 'End':   next = buttons.length - 1; break;
      default: return;
    }

    e.preventDefault();
    buttons[next].focus();
    this.#select(buttons[next].dataset.value);
  };
}
