import { describe, expect, it, vi } from 'vitest'

import { AppShell, TopMenuBar, createProductShell, createTopMenuBar } from './app-shell'

describe('TopMenuBar', () => {
  it('renders product breadcrumb, icon actions, and user menu actions', () => {
    const onSettings = vi.fn()
    const topbar = new TopMenuBar({
      product: 'Threat Library',
      current: 'Library Dashboard',
      actions: [{ id: 'notifications', label: 'Notifications', icon: 'bell', badge: true }],
      user: {
        name: 'Wyatt Roersma',
        detail: 'Threat Library',
        initials: 'WR',
        actions: [{ id: 'settings', label: 'Settings', icon: 'settings', onClick: onSettings }],
      },
    })

    expect(topbar.el.classList.contains('cmm-topbar')).toBe(true)
    expect(topbar.el.querySelector('.cmm-topbar__product')?.textContent).toBe('Threat Library')
    expect(topbar.el.querySelector('.cmm-topbar__current')?.textContent).toBe('Library Dashboard')
    expect(topbar.el.querySelector('[data-action-id="notifications"]')).toBeTruthy()
    expect(topbar.el.querySelector('.cmm-topbar__avatar')?.textContent).toBe('WR')

    const trigger = topbar.el.querySelector<HTMLButtonElement>('.cmm-topbar__user-trigger')
    const menu = topbar.el.querySelector<HTMLElement>('.cmm-topbar__user-menu')
    expect(menu?.hidden).toBe(true)

    trigger?.click()
    expect(trigger?.getAttribute('aria-expanded')).toBe('true')
    expect(menu?.hidden).toBe(false)

    topbar.el.querySelector<HTMLButtonElement>('[data-action-id="settings"]')?.click()
    expect(onSettings).toHaveBeenCalled()

    topbar.destroy()
    expect(document.body.contains(topbar.el)).toBe(false)
  })

  it('supports native custom action nodes and data-hook attributes', () => {
    const notificationWrapper = document.createElement('div')
    notificationWrapper.setAttribute('data-notification-wrapper', '')
    notificationWrapper.textContent = 'Notifications'

    const topbar = new TopMenuBar({
      product: 'CounterMeasure',
      current: 'Dashboard',
      actions: [
        {
          id: 'feedback',
          label: 'Feedback',
          showLabel: true,
          attributes: {
            'data-feedback-toggle': true,
            'aria-controls': 'feedback-panel',
          },
        },
        notificationWrapper,
        {
          id: 'help',
          label: 'Help',
          icon: 'circle-help',
          attributes: { 'data-help-toggle': true },
        },
      ],
    })

    const feedback = topbar.el.querySelector<HTMLElement>('[data-action-id="feedback"]')
    expect(feedback?.getAttribute('data-feedback-toggle')).toBe('')
    expect(feedback?.getAttribute('aria-controls')).toBe('feedback-panel')
    expect(feedback?.querySelector('.cmm-topbar__action-label')?.textContent).toBe('Feedback')
    expect(topbar.el.querySelector('[data-notification-wrapper]')).toBe(notificationWrapper)
    expect(topbar.el.querySelector('[data-help-toggle]')).toBeTruthy()
  })

  it('renders breadcrumbs, link actions, numeric badges, and outside-menu dismissal', () => {
    const container = document.createElement('div')
    const beforeAction = document.createElement('span')
    const afterAction = document.createElement('span')
    beforeAction.setAttribute('data-before-action', '')
    afterAction.setAttribute('data-after-action', '')
    document.body.appendChild(container)

    const topbar = new TopMenuBar({
      container,
      breadcrumbs: [{ label: 'Threat Library', href: '/threat-library' }, { label: 'Dashboards' }],
      current: 'Library',
      beforeActions: beforeAction,
      afterActions: [afterAction],
      actions: [
        {
          id: 'docs',
          label: 'Docs',
          href: '/docs',
          target: '_blank',
          icon: 'book-open',
          badge: 2,
          className: 'extra-action',
          attributes: {
            'data-docs-link': true,
            'data-nullish': null,
            'data-false': false,
          },
        },
      ],
      user: {
        name: 'Solo',
        avatarUrl: '/avatar.png',
        menuLabel: 'Account menu',
      },
    })

    const product = topbar.el.querySelector<HTMLElement>('.cmm-topbar__product')
    const docs = topbar.el.querySelector<HTMLAnchorElement>('[data-action-id="docs"]')
    const trigger = topbar.el.querySelector<HTMLButtonElement>('.cmm-topbar__user-trigger')
    const menu = topbar.el.querySelector<HTMLElement>('.cmm-topbar__user-menu')

    expect(container.querySelector('.cmm-topbar')).toBe(topbar.el)
    expect(product?.textContent).toBe('Threat Library')
    expect(topbar.el.querySelector('.cmm-topbar__breadcrumb')?.textContent).toBe('Dashboards')
    expect(docs?.tagName).toBe('A')
    expect(docs?.target).toBe('_blank')
    expect(docs?.rel).toBe('noreferrer noopener')
    expect(docs?.classList.contains('extra-action')).toBe(true)
    expect(docs?.getAttribute('data-docs-link')).toBe('')
    expect(docs?.hasAttribute('data-nullish')).toBe(false)
    expect(docs?.hasAttribute('data-false')).toBe(false)
    expect(docs?.querySelector('.cmm-topbar__action-badge')?.textContent).toBe('2')
    expect(topbar.el.querySelector('[data-before-action]')).toBe(beforeAction)
    expect(topbar.el.querySelector('[data-after-action]')).toBe(afterAction)
    expect(topbar.el.querySelector('.cmm-topbar__avatar img')?.getAttribute('src')).toBe(
      '/avatar.png'
    )
    expect(trigger?.getAttribute('aria-label')).toBe('Account menu')

    trigger?.click()
    expect(menu?.hidden).toBe(false)

    document.body.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true }))
    expect(menu?.hidden).toBe(true)

    trigger?.click()
    document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
    expect(menu?.hidden).toBe(true)

    topbar.destroy()
    container.remove()
  })

  it('composes a product app shell with topbar and content', () => {
    const sidebar = document.createElement('aside')
    const content = document.createElement('section')
    content.textContent = 'Dashboard content'

    const shell = new AppShell({
      sidebar,
      topbar: {
        product: 'Threat Library',
        current: 'Library Dashboard',
      },
      content,
      variant: 'product',
      sidebarCollapsed: false,
    })

    expect(shell.el.classList.contains('cmm-app-shell--product')).toBe(true)
    expect(shell.el.getAttribute('data-sidebar-collapsed')).toBe('false')
    expect(shell.el.querySelector('.cmm-app-shell__sidebar')?.contains(sidebar)).toBe(true)
    expect(shell.el.querySelector('.cmm-topbar__current')?.textContent).toBe('Library Dashboard')
    expect(shell.contentEl.contains(content)).toBe(true)
  })

  it('provides factory helpers for app shell chrome', () => {
    expect(createTopMenuBar({ current: 'Capacity' }).classList.contains('cmm-topbar')).toBe(true)
    expect(createProductShell().classList.contains('cmm-app-shell--product')).toBe(true)
  })

  it('composes default shell slots, metrics, and prebuilt topbar elements', () => {
    const container = document.createElement('div')
    const topbar = document.createElement('nav')
    const metrics = document.createElement('section')
    document.body.appendChild(container)

    const shell = new AppShell({
      container,
      topbar,
      metrics,
      className: 'custom-shell',
    })

    expect(container.querySelector('.cmm-app-shell')).toBe(shell.el)
    expect(shell.el.classList.contains('custom-shell')).toBe(true)
    expect(shell.el.classList.contains('cmm-app-shell--product')).toBe(false)
    expect(shell.mainEl.contains(topbar)).toBe(true)
    expect(shell.el.querySelector('.cmm-app-shell__metric-strip')?.contains(metrics)).toBe(true)

    const headerOnly = document.createElement('header')
    const shellWithHeader = new AppShell({ header: headerOnly })
    expect(shellWithHeader.mainEl.contains(headerOnly)).toBe(true)

    container.remove()
  })
})
