/**
 * Non-side-effect class export for `<pagination-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/pagination`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * <pagination-ui page="1" total="10" siblings="1"></pagination-ui>
 *
 * Page navigation with prev/next buttons, page numbers, and ellipsis.
 * Shows: first, ..., siblings around current, ..., last.
 *
 * Events:
 *   page-change — { detail: { page } }
 */

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

export class UIPagination extends UIElement {
  static properties = {
    page:     { type: Number, default: 1, reflect: true },
    total:    { type: Number, default: 1, reflect: true },
    siblings: { type: Number, default: 1, reflect: true },
    variant:  { type: String, default: 'default', reflect: true },
  };

  static template = () => null;

  #nav = null;
  #bound = false;

  connected() {
    if (!this.#nav) {
      this.#nav = document.createElement('nav');
      this.#nav.setAttribute('slot', 'nav');
      this.#nav.setAttribute('aria-label', 'Pagination');
      this.appendChild(this.#nav);
    }

    if (!this.#bound) {
      this.#bound = true;
      this.#nav.addEventListener('click', this.#onClick);
    }
  }

  disconnected() {
    this.#nav?.removeEventListener('click', this.#onClick);
    this.#nav = null;
    this.#bound = false;
  }

  render() {
    if (!this.#nav) return;

    const page = Math.max(1, Math.min(this.page, this.total));
    const total = Math.max(1, this.total);
    const siblings = Math.max(0, this.siblings);

    const range = this.#buildRange(page, total, siblings);

    this.reconcile(
      this.#nav,
      range,
      (item) => item.key,
      (item, i, existing) => {
        if (existing) {
          this.#updateItem(existing, item, page);
          return existing;
        }
        return this.#createItem(item, page);
      },
    );
  }

  #buildRange(page, total, siblings) {
    const items = [];

    // Prev button
    items.push({ key: 'prev', type: 'prev', value: page - 1 });

    // Always show first
    items.push({ key: 'page-1', type: 'page', value: 1 });

    const start = Math.max(2, page - siblings);
    const end = Math.min(total - 1, page + siblings);

    // Left ellipsis
    if (start > 2) {
      items.push({ key: 'ellipsis-start', type: 'ellipsis' });
    }

    // Sibling pages
    for (let i = start; i <= end; i++) {
      items.push({ key: `page-${i}`, type: 'page', value: i });
    }

    // Right ellipsis
    if (end < total - 1) {
      items.push({ key: 'ellipsis-end', type: 'ellipsis' });
    }

    // Always show last (if more than 1 page)
    if (total > 1) {
      items.push({ key: `page-${total}`, type: 'page', value: total });
    }

    // Next button
    items.push({ key: 'next', type: 'next', value: page + 1 });

    return items;
  }

  #createItem(item, page) {
    if (item.type === 'ellipsis') {
      const span = document.createElement('span');
      span.setAttribute('data-ellipsis', '');
      span.textContent = '\u2026';
      return span;
    }

    const btn = document.createElement('button');
    btn.setAttribute('type', 'button');

    if (item.type === 'prev') {
      btn.setAttribute('data-prev', '');
      btn.setAttribute('aria-label', 'Previous page');
      btn.textContent = '\u2039';
    } else if (item.type === 'next') {
      btn.setAttribute('data-next', '');
      btn.setAttribute('aria-label', 'Next page');
      btn.textContent = '\u203A';
    } else {
      btn.setAttribute('data-page', '');
      btn.dataset.value = String(item.value);
      btn.textContent = String(item.value);
      btn.setAttribute('aria-label', `Page ${item.value}`);
    }

    this.#updateItem(btn, item, page);
    return btn;
  }

  #updateItem(el, item, page) {
    if (item.type === 'ellipsis') return;

    if (item.type === 'prev') {
      if (page <= 1) { el.setAttribute('disabled', ''); el.setAttribute('tabindex', '-1'); }
      else { el.removeAttribute('disabled'); el.setAttribute('tabindex', '0'); }
    } else if (item.type === 'next') {
      if (page >= this.total) { el.setAttribute('disabled', ''); el.setAttribute('tabindex', '-1'); }
      else { el.removeAttribute('disabled'); el.setAttribute('tabindex', '0'); }
    } else {
      el.dataset.value = String(item.value);
      el.textContent = String(item.value);
      el.setAttribute('aria-label', `Page ${item.value}`);
      if (item.value === page) {
        el.setAttribute('data-active', '');
        el.setAttribute('aria-current', 'page');
      } else {
        el.removeAttribute('data-active');
        el.removeAttribute('aria-current');
      }
    }
  }

  #onClick = (e) => {
    const btn = e.target.closest('[data-prev], [data-next], [data-page]');
    if (!btn || btn.hasAttribute('disabled') || !this.#nav.contains(btn)) return;

    let newPage;

    if (btn.hasAttribute('data-prev')) {
      newPage = this.page - 1;
    } else if (btn.hasAttribute('data-next')) {
      newPage = this.page + 1;
    } else if (btn.hasAttribute('data-page')) {
      newPage = Number(btn.dataset.value);
    }

    if (newPage == null || newPage < 1 || newPage > this.total || newPage === this.page) return;

    this.page = newPage;
    this.dispatchEvent(new CustomEvent('page-change', {
      bubbles: true,
      detail: { page: this.page },
    }));
  };
}
