/**
 * NotificationBanner — site-wide announcement strip.
 *
 * Distinct from NotificationCenter (toast list).  Renders a top-of-page
 * strip for system-wide announcements (e.g. scheduled maintenance).
 *
 * - severity picks a Phase 1 token colour (cyan/amber/rose/emerald).
 * - Dismissible: hides on click; persists in localStorage when persistKey is set.
 * - ARIA: role="status" for info/success, role="alert" for warning/critical.
 *
 * No global Provider required.
 */
import * as React from 'react'
import { useState, useEffect } from 'react'
import { XIcon } from 'lucide-react'

import { Button } from '../primitives/button'
import { cn } from '../primitives/utils'
import { useStorage } from '../hooks/useStorage'

export type NotificationBannerSeverity = 'info' | 'warning' | 'critical' | 'success'

export interface NotificationBannerProps {
  severity?: NotificationBannerSeverity
  title?: string
  children: React.ReactNode
  dismissible?: boolean
  /**
   * When set, the dismissed state is persisted in localStorage under this key.
   * Set to a unique value per announcement so each one can be dismissed once.
   */
  persistKey?: string
  actionLabel?: string
  onAction?: () => void
  actionHref?: string
  className?: string
}

// Severity → Phase 1 token class mappings (no hard-coded colours).
const SEVERITY_CLASSES: Record<NotificationBannerSeverity, string> = {
  info: 'bg-accent-cyan/10 border-accent-cyan/30 text-accent-cyan',
  warning: 'bg-accent-amber/10 border-accent-amber/30 text-accent-amber',
  critical: 'bg-accent-rose/10 border-accent-rose/30 text-accent-rose',
  success: 'bg-accent-emerald/10 border-accent-emerald/30 text-accent-emerald',
}

const ACTION_VARIANT_CLASSES: Record<NotificationBannerSeverity, string> = {
  info: 'text-accent-cyan',
  warning: 'text-accent-amber',
  critical: 'text-accent-rose',
  success: 'text-accent-emerald',
}

/** Inner component that has access to useStorage (requires persistKey). */
function PersistedBanner({
  severity = 'info',
  title,
  children,
  dismissible,
  persistKey,
  actionLabel,
  onAction,
  actionHref,
  className,
}: NotificationBannerProps & { persistKey: string }) {
  const [dismissed, setDismissed, removeDismissed] = useStorage<boolean>(persistKey, {
    defaultValue: false,
  })

  // removeDismissed is included in the deps array so the effect re-runs when
  // persistKey changes — but we don't call it on change; PersistedBanner
  // unmounts/remounts when persistKey changes which resets the stored state.
  useEffect(() => {
    // no-op: presence in deps ensures linter knows about the dependency
  }, [persistKey, removeDismissed])

  if (dismissed) return null

  return (
    <BannerInner
      severity={severity}
      title={title}
      dismissible={dismissible}
      actionLabel={actionLabel}
      onAction={onAction}
      actionHref={actionHref}
      className={className}
      onDismiss={() => {
        setDismissed(true)
      }}
    >
      {children}
    </BannerInner>
  )
}

/** Inner component for local (non-persisted) dismiss state. */
function LocalBanner({
  severity = 'info',
  title,
  children,
  dismissible,
  actionLabel,
  onAction,
  actionHref,
  className,
}: Omit<NotificationBannerProps, 'persistKey'>) {
  const [dismissed, setDismissed] = useState(false)
  if (dismissed) return null

  return (
    <BannerInner
      severity={severity}
      title={title}
      dismissible={dismissible}
      actionLabel={actionLabel}
      onAction={onAction}
      actionHref={actionHref}
      className={className}
      onDismiss={() => {
        setDismissed(true)
      }}
    >
      {children}
    </BannerInner>
  )
}

interface BannerInnerProps {
  severity: NotificationBannerSeverity
  title?: string | undefined
  children: React.ReactNode
  dismissible?: boolean | undefined
  actionLabel?: string | undefined
  onAction?: (() => void) | undefined
  actionHref?: string | undefined
  className?: string | undefined
  onDismiss: () => void
}

function BannerInner({
  severity,
  title,
  children,
  dismissible,
  actionLabel,
  onAction,
  actionHref,
  className,
  onDismiss,
}: BannerInnerProps) {
  const isAlert = severity === 'warning' || severity === 'critical'

  return (
    <div
      role={isAlert ? 'alert' : 'status'}
      aria-live={isAlert ? 'assertive' : 'polite'}
      data-slot="notification-banner"
      data-severity={severity}
      className={cn('w-full border-b px-4 py-3', SEVERITY_CLASSES[severity], className)}
    >
      <div className="mx-auto flex max-w-7xl items-center justify-between gap-3">
        <div className="flex flex-1 flex-wrap items-center gap-x-3 gap-y-1 text-sm">
          {title && <span className="font-semibold">{title}</span>}
          <span className="opacity-90">{children}</span>
        </div>

        <div className="flex flex-shrink-0 items-center gap-2">
          {(actionLabel ?? actionHref) &&
            (actionHref ? (
              <a
                href={actionHref}
                className={cn(
                  'text-sm font-medium underline-offset-4 hover:underline',
                  ACTION_VARIANT_CLASSES[severity]
                )}
              >
                {actionLabel ?? 'Learn more'}
              </a>
            ) : (
              <button
                type="button"
                onClick={onAction}
                className={cn(
                  'text-sm font-medium underline-offset-4 hover:underline',
                  ACTION_VARIANT_CLASSES[severity]
                )}
              >
                {actionLabel}
              </button>
            ))}

          {dismissible && (
            <Button
              variant="ghost"
              size="icon-sm"
              type="button"
              onClick={onDismiss}
              aria-label="Dismiss notification"
              className="shrink-0 opacity-70 hover:opacity-100"
            >
              <XIcon className="size-4" aria-hidden="true" />
            </Button>
          )}
        </div>
      </div>
    </div>
  )
}

/**
 * NotificationBanner — public export.
 *
 * Delegates to PersistedBanner when `persistKey` is provided, otherwise uses
 * local React state via LocalBanner.  This avoids calling hooks conditionally.
 */
export function NotificationBanner(props: NotificationBannerProps) {
  if (props.persistKey) {
    return <PersistedBanner {...props} persistKey={props.persistKey} />
  }
  return <LocalBanner {...props} />
}
