import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import {
  <%= classify(name) %>,
  <%= classify(name) %>Item,
  <%= classify(name) %>Menu,
  <%= classify(name) %>Trigger,
} from './<%= dasherize(name) %>';

@Component({
  imports: [<%= classify(name) %>, <%= classify(name) %>Item, <%= classify(name) %>Menu, <%= classify(name) %>Trigger],
  template: `
    <div <%= camelize(name) %>>
      <button type="button" <%= camelize(name) %>Trigger>Options</button>
      <ul <%= camelize(name) %>Menu>
        @for (item of items; track item.id) {
          <li role="none">
            <div <%= camelize(name) %>Item>{{ item.label }}</div>
          </li>
        }
      </ul>
    </div>
  `,
})
class HostComponent {
  readonly items = [
    { id: 1, label: 'First option' },
    { id: 2, label: 'Second option' },
    { id: 3, label: 'Third option' },
  ];
}

describe('<%= classify(name) %>', () => {
  let fixture: ComponentFixture<HostComponent>;
  let host: HTMLElement;

  beforeEach(async () => {
    await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
    fixture = TestBed.createComponent(HostComponent);
    fixture.detectChanges();
    host = fixture.nativeElement as HTMLElement;
  });

  function trigger(): HTMLButtonElement {
    return host.querySelector('button')!;
  }

  function menu(): HTMLElement {
    return host.querySelector('[role="menu"]')!;
  }

  function menuItems(): HTMLElement[] {
    return Array.from(host.querySelectorAll('[role="menuitem"]'));
  }

  it('starts closed with consumer-owned menu button semantics', () => {
    expect(trigger().getAttribute('aria-haspopup')).toBe('true');
    expect(trigger().getAttribute('aria-expanded')).toBe('false');
    expect(trigger().getAttribute('aria-controls')).toBe(menu().id);
    expect(menu().hidden).toBe(true);
  });

  it('opens from click and wires menu labelling', () => {
    trigger().click();
    fixture.detectChanges();

    expect(trigger().getAttribute('aria-expanded')).toBe('true');
    expect(menu().hidden).toBe(false);
    expect(menu().getAttribute('aria-labelledby')).toBe(trigger().id);
    expect(menuItems()[0].textContent?.trim()).toBe('First option');
  });

  it('opens with keyboard and closes with Escape, returning focus to the trigger', () => {
    trigger().dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
    fixture.detectChanges();
    expect(menu().hidden).toBe(false);

    menuItems()[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
    fixture.detectChanges();

    expect(menu().hidden).toBe(true);
    expect(document.activeElement).toBe(trigger());
  });

  it('moves focus between menu items with ArrowDown/ArrowUp', () => {
    trigger().click();
    fixture.detectChanges();

    menuItems()[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
    fixture.detectChanges();

    expect(document.activeElement).toBe(menuItems()[1]);
  });

  it('closes on an outside click without selecting an item', () => {
    trigger().click();
    fixture.detectChanges();

    document.body.dispatchEvent(new MouseEvent('click', { bubbles: true }));
    fixture.detectChanges();

    expect(trigger().getAttribute('aria-expanded')).toBe('false');
    expect(menu().hidden).toBe(true);
  });
});
