/**
 * Collapsible - Animated expand/collapse container
 *
 * Uses CSS grid for smooth height animation without JavaScript measurement.
 * Provides both controlled and uncontrolled modes.
 */

import { createContext, useContext, useState, type ReactNode } from 'react'
import { ChevronDown, ChevronUp } from 'lucide-react'
import { cn } from './utils'

interface CollapsibleContextValue {
  isOpen: boolean
  toggle: () => void
}

const CollapsibleContext = createContext<CollapsibleContextValue | null>(null)

function useCollapsible() {
  const context = useContext(CollapsibleContext)
  if (!context) {
    throw new Error('Collapsible components must be used within a Collapsible')
  }
  return context
}

interface CollapsibleProps {
  children: ReactNode
  defaultOpen?: boolean
  open?: boolean
  onOpenChange?: (open: boolean) => void
  className?: string
}

/**
 * Root collapsible container
 */
function Collapsible({
  children,
  defaultOpen = true,
  open: controlledOpen,
  onOpenChange,
  className,
}: CollapsibleProps) {
  const [internalOpen, setInternalOpen] = useState(defaultOpen)

  const isControlled = controlledOpen !== undefined
  const isOpen = isControlled ? controlledOpen : internalOpen

  const toggle = () => {
    if (isControlled) {
      onOpenChange?.(!controlledOpen)
    } else {
      setInternalOpen(prev => !prev)
    }
  }

  return (
    <CollapsibleContext.Provider value={{ isOpen, toggle }}>
      <div className={className}>{children}</div>
    </CollapsibleContext.Provider>
  )
}

interface CollapsibleTriggerProps {
  children?: ReactNode
  className?: string
  showIcon?: boolean
}

/**
 * Button that toggles the collapsible
 */
function CollapsibleTrigger({ children, className, showIcon = true }: CollapsibleTriggerProps) {
  const { isOpen, toggle } = useCollapsible()

  return (
    <button
      type="button"
      onClick={toggle}
      className={cn(
        'text-foreground-muted hover:bg-accent hover:text-foreground-secondary rounded-lg p-1.5 transition-colors',
        className
      )}
      aria-expanded={isOpen}
    >
      {children ||
        (showIcon &&
          (isOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />))}
    </button>
  )
}

interface CollapsibleContentProps {
  children: ReactNode
  className?: string
}

/**
 * Animated content container
 * Uses CSS grid trick for smooth height animation
 */
function CollapsibleContent({ children, className }: CollapsibleContentProps) {
  const { isOpen } = useCollapsible()

  return (
    <div
      className={cn(
        'grid transition-[grid-template-rows] duration-300 ease-out',
        isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'
      )}
    >
      <div className={cn('overflow-hidden', className)}>{children}</div>
    </div>
  )
}

export { Collapsible, CollapsibleTrigger, CollapsibleContent }
