/**
 * <menu-ui> behavioral tests.
 *
 * FEEDBACK-92 (2026-05-31): `#show()` collected items with a direct-child
 * `:scope >` query, so items rendered through the template engine's
 * `.map()` / `repeat()` (each wrapped in a `display:contents` <span>) were
 * skipped → the popover opened empty. The fix uses a descendant query
 * (mirroring `#hide()`). These tests pin the dynamic + static paths.
 */

import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
import { html, stamp, repeat } from '../../core/template.js';

beforeAll(async () => {
  await import('../../core/element.js');
  await import('./menu.js');
  await import('../button/button.js');
});

const settle = () => new Promise((r) => setTimeout(r, 30));

describe('<menu-ui> collects dynamically-rendered items (FEEDBACK-92)', () => {
  let host;

  beforeEach(() => {
    host = document.createElement('div');
    document.body.appendChild(host);
  });
  afterEach(() => host.remove());

  function popItems(menu) {
    const pop = menu.querySelector('[data-menu-popover]');
    return pop ? pop.querySelectorAll('menu-item-ui') : [];
  }

  it('populates the popover from `.map()`-rendered items (the bug)', async () => {
    const ITEMS = [{ id: 'a', text: 'Alpha' }, { id: 'b', text: 'Beta' }];
    // Render the menu (closed) the documented way — items via `.map()`. The
    // consumer opens it later via interaction, after the template has rendered.
    stamp(html`
      <menu-ui>
        <button-ui slot="trigger" text="Open"></button-ui>
        ${ITEMS.map((i) => html`<menu-item-ui .text=${i.text} .value=${i.id}></menu-item-ui>`)}
      </menu-ui>
    `, host);
    await settle();

    const menu = host.querySelector('menu-ui');
    // The exact bug condition: items exist under the host but are NOT direct
    // children — the template engine nested them inside display:contents spans,
    // which the old `:scope >` query in #show() could not see.
    expect(menu.querySelectorAll('menu-item-ui').length).toBe(2);
    expect(menu.querySelector(':scope > menu-item-ui')).toBeNull();

    menu.open = true; // user opens the menu post-render
    await settle();

    const items = popItems(menu);
    expect(items.length).toBe(2);
    expect([...items].map((el) => el.value)).toEqual(['a', 'b']);
  });

  it('populates the popover from `repeat()`-rendered items', async () => {
    const ITEMS = [{ id: 'x', text: 'Ex' }, { id: 'y', text: 'Why' }, { id: 'z', text: 'Zee' }];
    stamp(html`
      <menu-ui>
        <button-ui slot="trigger" text="Open"></button-ui>
        ${repeat(ITEMS, (i) => i.id, (i) => html`<menu-item-ui .text=${i.text} .value=${i.id}></menu-item-ui>`)}
      </menu-ui>
    `, host);
    await settle();

    const menu = host.querySelector('menu-ui');
    expect(menu.querySelector(':scope > menu-item-ui')).toBeNull(); // behind wrappers
    menu.open = true;
    await settle();
    expect(popItems(menu).length).toBe(3);
  });

  it('still populates from static literal children (no regression)', async () => {
    const menu = document.createElement('menu-ui');
    menu.innerHTML = `
      <button-ui slot="trigger" text="Open"></button-ui>
      <menu-item-ui text="Edit" value="edit"></menu-item-ui>
      <menu-divider-ui></menu-divider-ui>
      <menu-item-ui text="Delete" value="delete"></menu-item-ui>`;
    host.appendChild(menu);
    await settle();
    menu.open = true;
    await settle();

    expect(popItems(menu).length).toBe(2);
    const pop = menu.querySelector('[data-menu-popover]');
    expect(pop.querySelectorAll('menu-divider-ui').length).toBe(1);
  });

  it('does not absorb the trigger into the popover', async () => {
    const menu = document.createElement('menu-ui');
    menu.innerHTML = `
      <button-ui slot="trigger" text="Open"></button-ui>
      <menu-item-ui text="Edit" value="edit"></menu-item-ui>`;
    host.appendChild(menu);
    await settle();
    menu.open = true;
    await settle();

    const pop = menu.querySelector('[data-menu-popover]');
    expect(pop.querySelector('[slot="trigger"]')).toBeNull();
    expect(menu.querySelector(':scope > [slot="trigger"]')).not.toBeNull();
  });

  it('does not reorder items on a re-entrant #show() (open → re-render → still open)', async () => {
    const menu = document.createElement('menu-ui');
    menu.innerHTML = `
      <button-ui slot="trigger" text="Open"></button-ui>
      <menu-item-ui text="One" value="1"></menu-item-ui>
      <menu-item-ui text="Two" value="2"></menu-item-ui>`;
    host.appendChild(menu);
    await settle();
    menu.open = true;
    await settle();
    // Force another render() pass while still open (re-invokes #show()).
    menu.placement = 'top-start';
    await settle();

    const pop = menu.querySelector('[data-menu-popover]');
    const order = [...pop.querySelectorAll('menu-item-ui')].map((el) => el.value);
    expect(order).toEqual(['1', '2']);
  });
});

describe('<menu-label-ui> group heading', () => {
  let host;
  beforeEach(() => { host = document.createElement('div'); document.body.appendChild(host); });
  afterEach(() => host.remove());

  it('hoists labels into the popover, stamps [text], and marks them presentational', async () => {
    const menu = document.createElement('menu-ui');
    menu.innerHTML = `
      <button-ui slot="trigger" text="Open"></button-ui>
      <menu-label-ui text="Group A"></menu-label-ui>
      <menu-item-ui text="One" value="1"></menu-item-ui>
      <menu-divider-ui></menu-divider-ui>
      <menu-label-ui text="Group B"></menu-label-ui>
      <menu-item-ui text="Two" value="2"></menu-item-ui>`;
    host.appendChild(menu);
    await settle();
    menu.open = true;
    await settle();

    const pop = menu.querySelector('[data-menu-popover]');
    const labels = pop.querySelectorAll('menu-label-ui');
    expect(labels.length).toBe(2);
    expect(labels[0].getAttribute('role')).toBe('presentation');
    expect(labels[0].textContent.trim()).toBe('Group A');
    expect(labels[1].textContent.trim()).toBe('Group B');
  });

  it('is non-interactive — outside the menuitem set the roving focus queries', async () => {
    const menu = document.createElement('menu-ui');
    menu.innerHTML = `
      <button-ui slot="trigger" text="Open"></button-ui>
      <menu-label-ui text="Heading"></menu-label-ui>
      <menu-item-ui text="One" value="1"></menu-item-ui>`;
    host.appendChild(menu);
    await settle();
    menu.open = true;
    await settle();

    const pop = menu.querySelector('[data-menu-popover]');
    // A label is neither a menu-item-ui nor role="menuitem", so #enabledItems()
    // (a `menu-item-ui` query) never lands arrow-key focus on it.
    expect(pop.querySelector('menu-label-ui[role="menuitem"]')).toBeNull();
    expect(pop.querySelectorAll('menu-item-ui').length).toBe(1);
  });
});
