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

import { SidebarComponent } from '../sidebar/component'
import {
  createCoreAppChromePreset,
  createCoreAppSidebarConfig,
  createCoreAppSidebarSections,
  createCoreAppTopbarActions,
  createCoreAppTopbarConfig,
  getCoreAppRouteLabel,
  mountCoreAppChrome,
  mountCoreAppChromeFromDom,
} from './core-app-chrome'

describe('core app chrome preset', () => {
  beforeEach(() => {
    localStorage.clear()
    window.history.replaceState({}, '', '/app')
  })

  it('creates the Threat Library sidebar sections under the native /app base path', () => {
    const sections = createCoreAppSidebarSections('/app')

    expect(sections).toHaveLength(5)
    expect(sections[0]?.label).toBe('Dashboards')
    expect(sections[0]?.items[0]).toMatchObject({
      id: 'library',
      label: 'Library',
      href: '/app',
      activeMatch: 'exact',
      end: true,
    })
    expect(sections[0]?.items[1]).toMatchObject({
      id: 'capacity',
      href: '/app/capacity',
      activeMatch: 'prefix',
    })
    expect(sections[3]?.items[1]).toMatchObject({
      id: 'jobs',
      href: '/app/jobs',
      icon: 'jobs',
    })
  })

  it('maps native app routes to topbar labels', () => {
    expect(getCoreAppRouteLabel('/app')).toBe('Platform Overview')
    expect(getCoreAppRouteLabel('/app/dashboards/library')).toBe('Library Dashboard')
    expect(getCoreAppRouteLabel('/app/jobs')).toBe('Jobs')
    expect(getCoreAppRouteLabel('/app/api-access/tokens')).toBe('API Access')
    expect(getCoreAppRouteLabel('/app/unknown')).toBe('Threat Library')
  })

  it('builds a product sidebar config with tenant scope and native behavior defaults', () => {
    const config = createCoreAppSidebarConfig({
      basePath: '/app',
      scope: {
        label: 'Tenant',
        value: 'all',
        options: [{ id: 'all', label: 'All Tenants' }],
      },
    })

    expect(config.variant).toBe('cm')
    expect(config.brand).toMatchObject({ label: 'CounterMeasure', href: '/app' })
    expect(config.scope?.options[0]?.label).toBe('All Tenants')
    expect(config.collapsible).toBe(true)
    expect(config.collapseButtonVisible).toBe(true)
    expect(config.storageKey).toBe('cm-sidebar-collapsed')
    expect(config.mobileBackdrop).toBe(true)
    expect(config.closeOnNavigate).toBe(true)
  })

  it('creates topbar defaults with native action hooks', () => {
    const actions = createCoreAppTopbarActions()
    const config = createCoreAppTopbarConfig({ pathname: '/app/jobs' })

    expect(actions).toHaveLength(3)
    expect(config.product).toBe('CounterMeasure Core')
    expect(config.current).toBe('Jobs')
    expect(config.actions?.[0]).toMatchObject({
      id: 'search',
      label: 'Find...',
      icon: 'search',
      attributes: { 'data-app-search-trigger': true },
    })
    expect(config.actions?.[1]).toMatchObject({
      id: 'feedback',
      attributes: { 'data-feedback-toggle': true },
    })
    expect(config.actions?.[2]).toMatchObject({
      id: 'help',
      icon: 'help',
      attributes: { 'data-help-toggle': true },
    })
  })

  it('supports custom topbar action sets and optional topbar config fields', () => {
    const container = document.createElement('div')
    const beforeActions = document.createElement('span')
    const afterActions = document.createElement('span')
    const user = { name: 'Wyatt Roersma', detail: 'Core' }

    beforeActions.setAttribute('data-before', '')
    afterActions.setAttribute('data-after', '')

    expect(
      createCoreAppTopbarActions({
        includeSearchAction: false,
        includeFeedbackAction: false,
        includeHelpAction: false,
      })
    ).toEqual([])

    const customAction = { id: 'custom', label: 'Custom', attributes: { 'data-custom': true } }
    const config = createCoreAppTopbarConfig({
      container,
      product: 'Core',
      current: 'Custom Page',
      breadcrumbs: [{ label: 'Platform' }],
      actions: [customAction],
      beforeActions,
      afterActions,
      user,
      iconSet: 'lucide',
      className: 'core-extra',
      includeSearchAction: false,
    })

    expect(config.container).toBe(container)
    expect(config.product).toBe('Core')
    expect(config.current).toBe('Custom Page')
    expect(config.actions).toEqual([customAction])
    expect(config.beforeActions).toBe(beforeActions)
    expect(config.afterActions).toBe(afterActions)
    expect(config.user).toBe(user)
    expect(config.iconSet).toBe('lucide')
    expect(config.className).toBe('core-extra')
  })

  it('copies custom sidebar sections and applies optional sidebar config fields', () => {
    const beforeNav = document.createElement('div')
    const afterNav = document.createElement('div')
    const onNavigate = vi.fn()
    const sections = [
      {
        id: 'custom',
        items: [{ id: 'custom-item', label: 'Custom', href: '/custom' }],
      },
    ]

    const config = createCoreAppSidebarConfig({
      basePath: '/',
      sections,
      variant: 'threat-library',
      brand: { label: 'Library', href: '/library' },
      beforeNav,
      afterNav,
      user: { name: 'Analyst' },
      footerActions: [{ id: 'settings', label: 'Settings', icon: 'settings' }],
      iconSet: 'lucide',
      collapsed: true,
      activeItemId: 'custom-item',
      pathname: '/custom',
      persistCollapsed: false,
      mobileBreakpoint: 640,
      open: true,
      onNavigate,
      onCollapse: vi.fn(),
      onOpenChange: vi.fn(),
    })

    sections[0]?.items.push({ id: 'later', label: 'Later', href: '/later' })

    expect(config.variant).toBe('threat-library')
    expect(config.sections).toHaveLength(1)
    expect(config.sections[0]?.items).toHaveLength(1)
    expect(config.brand).toMatchObject({ label: 'Library', href: '/library' })
    expect(config.beforeNav).toBe(beforeNav)
    expect(config.afterNav).toBe(afterNav)
    expect(config.user?.name).toBe('Analyst')
    expect(config.footerActions?.[0]?.id).toBe('settings')
    expect(config.iconSet).toBe('lucide')
    expect(config.collapsed).toBe(true)
    expect(config.activeItemId).toBe('custom-item')
    expect(config.pathname).toBe('/custom')
    expect(config.persistCollapsed).toBe(false)
    expect(config.mobileBreakpoint).toBe(640)
    expect(config.open).toBe(true)
    expect(config.onNavigate).toBe(onNavigate)
  })

  it('renders the preset as an active product sidebar for native /app routes', () => {
    window.history.replaceState({}, '', '/')
    const container = document.createElement('div')
    document.body.appendChild(container)

    const preset = createCoreAppChromePreset({ basePath: '/app', pathname: '/app/jobs' })
    const sidebar = new SidebarComponent({ container, ...preset.sidebar })

    const aside = container.querySelector<HTMLElement>('.sidebar')
    const active = container.querySelector<HTMLElement>('[data-item-id="jobs"]')
    const library = container.querySelector<HTMLElement>('[data-item-id="library"]')

    expect(preset.topbar.current).toBe('Jobs')
    expect(preset.sidebar.pathname).toBe('/app/jobs')
    expect(aside?.classList.contains('sidebar--product')).toBe(true)
    expect(aside?.getAttribute('data-sidebar')).toBe('cm')
    expect(active?.classList.contains('sidebar__item--active')).toBe(true)
    expect(active?.getAttribute('aria-current')).toBe('page')
    expect(library?.classList.contains('sidebar__item--active')).toBe(false)

    sidebar.destroy()
    container.remove()
  })

  it('mounts and destroys native app chrome in server-rendered containers', () => {
    window.history.replaceState({}, '', '/')
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const serverPlaceholder = document.createElement('span')
    const notificationAction = document.createElement('button')

    serverPlaceholder.textContent = 'server sidebar'
    notificationAction.type = 'button'
    notificationAction.setAttribute('data-notification-toggle', '')
    notificationAction.textContent = 'Notifications'
    sidebarContainer.appendChild(serverPlaceholder)
    document.body.append(sidebarContainer, topbarContainer)

    const mounted = mountCoreAppChrome({
      sidebarContainer,
      topbarContainer,
      basePath: '/app',
      pathname: '/app/jobs',
      scope: {
        label: 'Tenant',
        value: 'all',
        options: [{ id: 'all', label: 'All Tenants', status: 'neutral' }],
      },
      topbarActions: [notificationAction],
    })

    const aside = sidebarContainer.querySelector<HTMLElement>('.sidebar')
    const topbar = topbarContainer.querySelector<HTMLElement>('.cmm-topbar')
    const active = sidebarContainer.querySelector<HTMLElement>('[data-item-id="jobs"]')

    expect(serverPlaceholder.isConnected).toBe(false)
    expect(aside?.classList.contains('sidebar--product')).toBe(true)
    expect(active?.classList.contains('sidebar__item--active')).toBe(true)
    expect(topbar?.querySelector('.cmm-topbar__current')?.textContent).toBe('Jobs')
    expect(topbar?.querySelector('[data-notification-toggle]')).toBe(notificationAction)
    expect(sidebarContainer.querySelector('.sidebar__scope-current')?.textContent).toBe(
      'All Tenants'
    )

    mounted.destroy()
    expect(sidebarContainer.querySelector('.sidebar')).toBeNull()
    expect(topbarContainer.querySelector('.cmm-topbar')).toBeNull()

    sidebarContainer.remove()
    topbarContainer.remove()
  })

  it('preserves explicitly marked native topbar action nodes during mount', () => {
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const action = document.createElement('button')
    const beforeActions = document.createElement('span')

    action.type = 'button'
    action.setAttribute('data-core-app-topbar-action', '')
    action.setAttribute('data-notification-toggle', '')
    action.textContent = 'Notifications'
    beforeActions.setAttribute('data-before-actions', '')
    topbarContainer.appendChild(action)
    document.body.append(sidebarContainer, topbarContainer)

    const mounted = mountCoreAppChrome({
      sidebarContainer,
      topbarContainer,
      pathname: '/app',
      topbar: { afterActions: beforeActions },
    })

    const topbar = topbarContainer.querySelector<HTMLElement>('.cmm-topbar')
    expect(topbar?.querySelector('[data-app-search-trigger]')).toBeTruthy()
    expect(topbar?.querySelector('[data-before-actions]')).toBe(beforeActions)
    expect(topbar?.querySelector('[data-notification-toggle]')).toBe(action)
    expect(action.isConnected).toBe(true)

    mounted.destroy()
    sidebarContainer.remove()
    topbarContainer.remove()
  })

  it('dedupes preserved default action nodes and supports no-topbar mounts', () => {
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const preservedSearch = document.createElement('button')
    const preservedFeedback = document.createElement('button')
    const preservedHelp = document.createElement('button')

    preservedSearch.setAttribute('data-core-app-topbar-action', '')
    preservedSearch.setAttribute('data-app-search-trigger', '')
    preservedFeedback.setAttribute('data-core-app-topbar-action', '')
    preservedFeedback.setAttribute('data-feedback-toggle', '')
    preservedHelp.setAttribute('data-core-app-topbar-action', '')
    preservedHelp.setAttribute('data-help-toggle', '')
    topbarContainer.append(preservedSearch, preservedFeedback, preservedHelp)
    document.body.append(sidebarContainer, topbarContainer)

    const mounted = mountCoreAppChrome({
      sidebarContainer,
      topbarContainer,
      pathname: '/app',
    })

    expect(topbarContainer.querySelectorAll('[data-app-search-trigger]')).toHaveLength(1)
    expect(topbarContainer.querySelectorAll('[data-feedback-toggle]')).toHaveLength(1)
    expect(topbarContainer.querySelectorAll('[data-help-toggle]')).toHaveLength(1)
    mounted.destroy()

    const sidebarOnlyContainer = document.createElement('div')
    document.body.appendChild(sidebarOnlyContainer)
    const sidebarOnly = mountCoreAppChrome({
      sidebarContainer: sidebarOnlyContainer,
      pathname: '/app',
    })

    expect(sidebarOnly.topbar).toBeUndefined()
    expect(sidebarOnlyContainer.querySelector('.sidebar')).toBeTruthy()

    sidebarOnly.destroy()
    sidebarContainer.remove()
    topbarContainer.remove()
    sidebarOnlyContainer.remove()
  })

  it('honors clear-container and preservation controls during mount', () => {
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const existingSidebar = document.createElement('p')
    const preserved = document.createElement('button')

    existingSidebar.textContent = 'existing'
    preserved.setAttribute('data-core-app-topbar-action', '')
    preserved.setAttribute('data-help-toggle', '')
    sidebarContainer.appendChild(existingSidebar)
    topbarContainer.appendChild(preserved)
    document.body.append(sidebarContainer, topbarContainer)

    const mounted = mountCoreAppChrome({
      sidebarContainer,
      topbarContainer,
      clearContainers: false,
      preserveTopbarActions: false,
      topbar: {
        includeSearchAction: false,
        includeFeedbackAction: false,
        includeHelpAction: true,
      },
    })

    expect(sidebarContainer.contains(existingSidebar)).toBe(true)
    expect(topbarContainer.contains(preserved)).toBe(true)
    expect(topbarContainer.querySelectorAll('[data-help-toggle]')).toHaveLength(2)

    mounted.destroy()
    sidebarContainer.remove()
    topbarContainer.remove()
  })

  it('mounts from declarative DOM placeholders', () => {
    window.history.replaceState({}, '', '/')
    const root = document.createElement('section')
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const action = document.createElement('button')

    sidebarContainer.setAttribute('data-core-app-sidebar', '')
    sidebarContainer.setAttribute('data-base-path', '/app')
    sidebarContainer.setAttribute('data-pathname', '/app/api-access/tokens')
    topbarContainer.setAttribute('data-core-app-topbar', '')
    topbarContainer.setAttribute('data-product', 'CounterMeasure Core')
    topbarContainer.setAttribute('data-current', 'API Tokens')
    action.type = 'button'
    action.setAttribute('data-core-app-topbar-action', '')
    action.setAttribute('data-help-toggle', '')
    action.textContent = 'Help'
    topbarContainer.appendChild(action)
    root.append(sidebarContainer, topbarContainer)
    document.body.appendChild(root)

    const mounted = mountCoreAppChromeFromDom({ root })

    expect(mounted).not.toBeNull()
    expect(sidebarContainer.querySelector('.sidebar--product')).toBeTruthy()
    expect(
      sidebarContainer.querySelector('[data-item-id="api-access"]')?.getAttribute('aria-current')
    ).toBe('page')
    expect(topbarContainer.querySelector('.cmm-topbar__product')?.textContent).toBe(
      'CounterMeasure Core'
    )
    expect(topbarContainer.querySelector('.cmm-topbar__current')?.textContent).toBe('API Tokens')
    expect(topbarContainer.querySelector('[data-help-toggle]')).toBe(action)

    mounted?.destroy()
    root.remove()
  })

  it('lets explicit topbar options override declarative labels', () => {
    const root = document.createElement('section')
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')

    sidebarContainer.setAttribute('data-core-app-sidebar', '')
    topbarContainer.setAttribute('data-core-app-topbar', '')
    topbarContainer.setAttribute('data-product', 'CounterMeasure Core')
    topbarContainer.setAttribute('data-current', 'Platform Overview')
    root.append(sidebarContainer, topbarContainer)
    document.body.appendChild(root)

    const mounted = mountCoreAppChromeFromDom({
      root,
      topbar: {
        product: 'Threat Library',
        current: 'Library Dashboard',
      },
    })

    expect(topbarContainer.querySelector('.cmm-topbar__product')?.textContent).toBe(
      'Threat Library'
    )
    expect(topbarContainer.querySelector('.cmm-topbar__current')?.textContent).toBe(
      'Library Dashboard'
    )

    mounted?.destroy()
    root.remove()
  })

  it('mounts from custom selectors and sidebar-provided declarative labels', () => {
    const root = document.createElement('section')
    const sidebarContainer = document.createElement('div')
    const topbarContainer = document.createElement('div')
    const customAction = document.createElement('button')

    sidebarContainer.setAttribute('data-custom-sidebar', '')
    sidebarContainer.setAttribute('data-base-path', '/native')
    sidebarContainer.setAttribute('data-pathname', '/native/connectors')
    sidebarContainer.setAttribute('data-product', 'Native Core')
    sidebarContainer.setAttribute('data-current', 'Native Connectors')
    topbarContainer.setAttribute('data-custom-topbar', '')
    customAction.setAttribute('data-preserved-action', '')
    customAction.setAttribute('data-app-search-trigger', '')
    topbarContainer.appendChild(customAction)
    root.append(sidebarContainer, topbarContainer)
    document.body.appendChild(root)

    const mounted = mountCoreAppChromeFromDom({
      root,
      sidebarSelector: '[data-custom-sidebar]',
      topbarSelector: '[data-custom-topbar]',
      topbarActionSelector: '[data-preserved-action]',
    })

    expect(mounted).not.toBeNull()
    expect(
      sidebarContainer.querySelector('[data-item-id="connectors"]')?.getAttribute('href')
    ).toBe('/native/connectors')
    expect(
      sidebarContainer.querySelector('[data-item-id="connectors"]')?.getAttribute('aria-current')
    ).toBe('page')
    expect(topbarContainer.querySelector('.cmm-topbar__product')?.textContent).toBe('Native Core')
    expect(topbarContainer.querySelector('.cmm-topbar__current')?.textContent).toBe(
      'Native Connectors'
    )
    expect(topbarContainer.querySelectorAll('[data-app-search-trigger]')).toHaveLength(1)

    mounted?.destroy()
    root.remove()
  })

  it('returns null when no declarative sidebar placeholder exists', () => {
    const root = document.createElement('section')

    expect(mountCoreAppChromeFromDom({ root })).toBeNull()
  })

  it('mounts declarative sidebar-only chrome when no topbar data is present', () => {
    const root = document.createElement('section')
    const sidebarContainer = document.createElement('div')

    sidebarContainer.setAttribute('data-core-app-sidebar', '')
    root.appendChild(sidebarContainer)
    document.body.appendChild(root)

    const mounted = mountCoreAppChromeFromDom({ root })

    expect(mounted).not.toBeNull()
    expect(mounted?.topbar).toBeUndefined()
    expect(sidebarContainer.querySelector('.sidebar--product')).toBeTruthy()

    mounted?.destroy()
    root.remove()
  })
})
