/**
 * AppSwitcher React wrapper — Lane A imperative wrap over src/app-switcher/index.ts
 *
 * Import from the dedicated subpath:
 *   import { AppSwitcher } from '@countermeasure-platform/web-components/react/app-switcher'
 *
 * ## Architecture note
 *
 * The vanilla `initAppSwitcher` function works by scanning `document` for
 * `[data-app-switcher]` elements and enhancing their inner structure. It
 * expects specific child elements with `data-*` attributes to already be
 * present in the DOM (grid, current, icon, trigger, panel).
 *
 * This wrapper is a **declarative shell + imperative init**: it renders the
 * complete DOM structure the vanilla module expects, then calls
 * `initAppSwitcher` inside `useEffect` with the app list passed as props.
 * This avoids duplicating the open/close/keyboard logic in React while
 * keeping the component SSR-safe (no DOM access during render).
 *
 * When `apps` changes the effect re-runs, tearing down (via a fresh render
 * triggered by a key) and re-initialising so the grid reflects the new list.
 */

import * as React from 'react'
import { cn } from './primitives/utils'
import { initAppSwitcher } from '../app-switcher/index'
import type { AppLink, AppSwitcherConfig } from '../app-switcher/index'

export interface AppSwitcherProps {
  /** List of apps to display in the switcher panel. */
  apps?: AppLink[]
  /** Optional function returning apps (called once on mount). */
  getApps?: AppSwitcherConfig['getApps']
  className?: string
}

export type { AppLink }

/**
 * Inner component that owns the DOM structure and the imperative init.
 * It is re-keyed by the parent when `apps` changes so the entire subtree
 * (including vanilla event listeners) is cleanly replaced.
 */
function AppSwitcherInner({ apps, getApps, className }: AppSwitcherProps) {
  const containerRef = React.useRef<HTMLDivElement>(null)

  React.useEffect(() => {
    if (typeof document === 'undefined' || !containerRef.current) return
    // initAppSwitcher queries [data-app-switcher] globally; we mark this node
    // then initialise with an explicit apps list so only our element is affected.
    const switcherConfig: { apps?: AppLink[]; getApps?: () => AppLink[] } = {}
    if (apps !== undefined) switcherConfig.apps = apps
    if (getApps !== undefined) switcherConfig.getApps = getApps
    initAppSwitcher(switcherConfig)
    // No explicit teardown: the vanilla module attaches click handlers on the
    // DOM nodes themselves. When React unmounts this component the nodes are
    // removed from the document and the handlers are garbage-collected.
  }, [apps, getApps])

  return (
    <div
      ref={containerRef}
      data-app-switcher
      data-slot="app-switcher"
      className={cn('app-switcher', className)}
      hidden
    >
      <button
        type="button"
        className="app-switcher__trigger"
        aria-haspopup="menu"
        aria-expanded="false"
      >
        <span data-app-switcher-icon aria-hidden="true" />
        <span data-app-switcher-current />
      </button>
      <div className="app-switcher__panel" role="menu">
        <div data-app-switcher-grid className="app-switcher__grid" />
      </div>
    </div>
  )
}

/**
 * AppSwitcher — React wrapper around the vanilla app-switcher module.
 *
 * Re-keys the inner component whenever `apps` changes so all vanilla
 * event listeners are cleanly re-attached on the fresh DOM.
 */
function AppSwitcher({ apps, getApps, className }: AppSwitcherProps) {
  // Serialise apps to a stable key so we only re-mount when the list truly changes.
  const appsKey = React.useMemo(() => (apps ? apps.map(a => a.id).join(',') : 'getApps'), [apps])

  return (
    <AppSwitcherInner
      key={appsKey}
      {...(apps !== undefined ? { apps } : {})}
      {...(getApps !== undefined ? { getApps } : {})}
      {...(className !== undefined ? { className } : {})}
    />
  )
}

AppSwitcher.displayName = 'AppSwitcher'

export { AppSwitcher }
