'use client'

import * as React from 'react'
import { useState } from 'react'
import { ChevronDown } from 'lucide-react'
import { cn } from '../../lib/utils'

export interface GroupedNavLink {
  href: string
  label: string
  icon?: React.ReactNode
  /** Optional trailing slot (count pill, status dot…). */
  badge?: React.ReactNode
}

export interface GroupedNavGroup {
  label: string
  icon?: React.ReactNode
  items: GroupedNavLink[]
  /** Start expanded (default true). Ignored while a child is active — then forced open. */
  defaultOpen?: boolean
  /** Show a chevron toggle (default true). false = a static section heading. */
  collapsible?: boolean
}

/** A top-level link, or a named group of links. Discriminated by `items`. */
export type GroupedNavEntry = GroupedNavLink | GroupedNavGroup

export interface GroupedNavRenderLinkArgs {
  link: GroupedNavLink
  active: boolean
  className: string
  /** The pre-composed inner content (icon + label + badge). */
  content: React.ReactNode
}

export interface GroupedNavProps {
  items: GroupedNavEntry[]
  /** The current path; drives active state. */
  activeHref?: string
  /** Override active matching (default: exact, or `activeHref` under `href/`). */
  isActive?: (href: string, activeHref?: string) => boolean
  /**
   * Render a link — pass `next/link` here in a Next app. Default renders a plain
   * `<a>` so the primitive stays framework-agnostic.
   */
  renderLink?: (args: GroupedNavRenderLinkArgs) => React.ReactNode
  className?: string
}

function isGroup(entry: GroupedNavEntry): entry is GroupedNavGroup {
  return Array.isArray((entry as GroupedNavGroup).items)
}

function defaultIsActive(href: string, activeHref?: string): boolean {
  if (!activeHref) return false
  if (href === '/') return activeHref === '/'
  return activeHref === href || activeHref.startsWith(href + '/')
}

const defaultRenderLink = ({ link, active, className, content }: GroupedNavRenderLinkArgs) => (
  <a href={link.href} className={className} aria-current={active ? 'page' : undefined}>
    {content}
  </a>
)

function linkClasses(active: boolean, indented: boolean) {
  return cn(
    'flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors',
    indented && 'pl-9',
    active
      ? 'bg-primary text-primary-foreground'
      : 'text-gray-700 hover:bg-gray-100 hover:text-gray-900',
  )
}

/**
 * A grouped sidebar navigation list: a mix of top-level links and collapsible
 * groups (e.g. Dashboard + a "Content" group of the three content types). Purely
 * the `<nav>` list — the app shell owns the logo, user footer, and chrome. Active
 * state and link rendering are injectable so it drops into any router.
 */
export function GroupedNav({
  items,
  activeHref,
  isActive = defaultIsActive,
  renderLink = defaultRenderLink,
  className,
}: GroupedNavProps) {
  return (
    <nav className={cn('space-y-1', className)} aria-label="Primary">
      {items.map((entry, idx) =>
        isGroup(entry) ? (
          <NavGroup
            key={`group-${entry.label}-${idx}`}
            group={entry}
            activeHref={activeHref}
            isActive={isActive}
            renderLink={renderLink}
          />
        ) : (
          <NavLinkRow
            key={entry.href}
            link={entry}
            active={isActive(entry.href, activeHref)}
            indented={false}
            renderLink={renderLink}
          />
        ),
      )}
    </nav>
  )
}

function NavLinkRow({
  link,
  active,
  indented,
  renderLink,
}: {
  link: GroupedNavLink
  active: boolean
  indented: boolean
  renderLink: NonNullable<GroupedNavProps['renderLink']>
}) {
  const content = (
    <>
      {link.icon ? <span className="flex-shrink-0 w-5 h-5 flex items-center justify-center">{link.icon}</span> : null}
      <span className="flex-1 truncate">{link.label}</span>
      {link.badge ? <span className="flex-shrink-0">{link.badge}</span> : null}
    </>
  )
  return <>{renderLink({ link, active, className: linkClasses(active, indented), content })}</>
}

function NavGroup({
  group,
  activeHref,
  isActive,
  renderLink,
}: {
  group: GroupedNavGroup
  activeHref?: string
  isActive: NonNullable<GroupedNavProps['isActive']>
  renderLink: NonNullable<GroupedNavProps['renderLink']>
}) {
  const collapsible = group.collapsible ?? true
  const hasActiveChild = group.items.some((l) => isActive(l.href, activeHref))
  const [open, setOpen] = useState(group.defaultOpen ?? true)
  const expanded = hasActiveChild || open

  const links = expanded
    ? group.items.map((link) => (
        <NavLinkRow
          key={link.href}
          link={link}
          active={isActive(link.href, activeHref)}
          indented
          renderLink={renderLink}
        />
      ))
    : null

  const heading = (
    <span className="flex items-center gap-2 min-w-0">
      {group.icon ? <span className="flex-shrink-0 w-5 h-5 flex items-center justify-center">{group.icon}</span> : null}
      <span className="text-xs font-semibold text-gray-400 uppercase tracking-wider truncate">{group.label}</span>
    </span>
  )

  return (
    <div className="pt-3 first:pt-0">
      {collapsible ? (
        <button
          type="button"
          onClick={() => setOpen((o) => !o)}
          aria-expanded={expanded}
          className="w-full flex items-center justify-between gap-2 px-3 py-1.5 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-ring"
        >
          {heading}
          <ChevronDown
            className={cn('w-4 h-4 text-gray-400 transition-transform flex-shrink-0', expanded ? '' : '-rotate-90')}
            aria-hidden="true"
          />
        </button>
      ) : (
        <div className="px-3 py-1.5">{heading}</div>
      )}
      {links && <div className="mt-1 space-y-1">{links}</div>}
    </div>
  )
}
