import { TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { UserMenu, type UserMenuItem } from './user-menu';

const ITEMS: readonly UserMenuItem[] = [
  { label: 'Profile', icon: 'user', routerLink: '/profile' },
  { label: 'Settings', icon: 'settings', disabled: true, badge: 'Soon' },
];

async function setup(overrides: Partial<Parameters<typeof renderWith>[0]> = {}) {
  await TestBed.configureTestingModule({
    imports: [UserMenu],
    providers: [provideRouter([])],
  }).compileComponents();
  return renderWith({
    displayName: 'Jane Doe',
    username: 'jane@apf.example',
    initials: 'JD',
    items: ITEMS,
    triggerAriaLabel: 'User menu — signed in as Jane Doe',
    ...overrides,
  });
}

function renderWith(opts: {
  displayName: string;
  username: string;
  initials: string;
  items: readonly UserMenuItem[];
  role?: string;
  signedInAsLabel?: string;
  signOutLabel?: string;
  triggerAriaLabel?: string;
}) {
  const fixture = TestBed.createComponent(UserMenu);
  fixture.componentRef.setInput('displayName', opts.displayName);
  fixture.componentRef.setInput('username', opts.username);
  fixture.componentRef.setInput('initials', opts.initials);
  fixture.componentRef.setInput('items', opts.items);
  if (opts.role) {
    fixture.componentRef.setInput('role', opts.role);
  }
  if (opts.signedInAsLabel) {
    fixture.componentRef.setInput('signedInAsLabel', opts.signedInAsLabel);
  }
  if (opts.signOutLabel) {
    fixture.componentRef.setInput('signOutLabel', opts.signOutLabel);
  }
  if (opts.triggerAriaLabel) {
    fixture.componentRef.setInput('triggerAriaLabel', opts.triggerAriaLabel);
  }
  fixture.detectChanges();
  return fixture;
}

describe('UserMenu', () => {
  it('renders the avatar trigger with initials + aria-label', async () => {
    const fixture = await setup();
    const trigger = (fixture.nativeElement as HTMLElement).querySelector(
      'button[aria-haspopup="menu"]',
    ) as HTMLButtonElement | null;
    expect(trigger).not.toBeNull();
    expect(trigger?.getAttribute('aria-label')).toBe('User menu — signed in as Jane Doe');
    expect(trigger?.querySelector('.user-menu__avatar')?.textContent?.trim()).toBe('JD');
  });

  it('renders the menu panel via the CDK overlay on trigger click', async () => {
    const fixture = await setup();
    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();

    // CDK Menu mounts the panel in an overlay portal at document
    // root, not under the component's host — scope the assertion to
    // the document.
    const panel = document.body.querySelector('.user-menu__panel');
    expect(panel).not.toBeNull();
    expect(panel?.querySelector('.user-menu__header-name')?.textContent).toContain('Jane Doe');
    expect(panel?.querySelector('.user-menu__header-username')?.textContent).toContain(
      'jane@apf.example',
    );
  });

  it('renders enabled items as router links and disabled items as aria-disabled rows', async () => {
    const fixture = await setup();
    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();
    const panel = document.body.querySelector('.user-menu__panel');

    const profile = panel?.querySelector('a.user-menu__item[href="/profile"]');
    expect(profile?.textContent).toContain('Profile');

    const settings = panel?.querySelector('.user-menu__item--disabled');
    expect(settings?.getAttribute('aria-disabled')).toBe('true');
    expect(settings?.querySelector('.user-menu__badge')?.textContent?.trim()).toBe('Soon');
  });

  it('emits signOut on Sign out click and uses the localised label', async () => {
    const fixture = await setup({ signOutLabel: 'Se déconnecter' });
    let emitted = 0;
    fixture.componentInstance.signOut.subscribe(() => emitted++);

    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();

    const signOut = document.body.querySelector<HTMLButtonElement>('.user-menu__item--sign-out');
    expect(signOut?.textContent).toContain('Se déconnecter');
    signOut?.click();
    expect(emitted).toBe(1);
  });

  it('renders an external link via `href` instead of routerLink when provided', async () => {
    const fixture = await setup({
      items: [{ label: 'Open elsewhere', href: 'https://example.test/' }],
    });
    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();

    const link = document.body.querySelector<HTMLAnchorElement>(
      '.user-menu__item[href="https://example.test/"]',
    );
    expect(link).not.toBeNull();
    expect(link?.textContent).toContain('Open elsewhere');
  });

  it('renders the role chip in the panel header when `role` is provided', async () => {
    const fixture = await setup({ role: 'Administrator' });
    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();
    const panel = document.body.querySelector('.user-menu__panel');
    const roleChip = panel?.querySelector('[data-testid="user-menu-role"]');
    expect(roleChip?.textContent?.trim()).toBe('Administrator');
  });

  it('omits the role chip when `role` is undefined', async () => {
    const fixture = await setup();
    const trigger = (fixture.nativeElement as HTMLElement).querySelector<HTMLButtonElement>(
      'button[aria-haspopup="menu"]',
    );
    trigger?.click();
    fixture.detectChanges();
    await fixture.whenStable();
    expect(document.body.querySelector('[data-testid="user-menu-role"]')).toBeNull();
  });
});
