import { useEffect, useRef, type ReactNode } from 'react'
import { createPortal } from 'react-dom'

type ModalProps = {
  open: boolean
  title?: string
  onClose: () => void
  children: ReactNode
  size?: 'md' | 'lg'
}

function focusable(root: HTMLElement | null): HTMLElement[] {
  if (!root) return []
  const sel = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  return Array.from(root.querySelectorAll<HTMLElement>(sel)).filter(
    (el) => !el.hasAttribute('disabled') && el.getAttribute('aria-hidden') !== 'true',
  )
}

// Reusable modal shell: portal to <body>, ESC to close, Tab focus-trap,
// focus-on-open (prefers [data-modal-autofocus]), focus restore on close,
// click-on-overlay to close, and body scroll lock while open.
export function Modal({ open, title, onClose, children, size = 'md' }: ModalProps) {
  const dialogRef = useRef<HTMLDivElement>(null)
  const prevFocus = useRef<HTMLElement | null>(null)
  const onCloseRef = useRef(onClose)
  onCloseRef.current = onClose

  useEffect(() => {
    if (!open) return
    prevFocus.current = document.activeElement as HTMLElement | null

    const auto = dialogRef.current?.querySelector<HTMLElement>('[data-modal-autofocus]')
    ;(auto ?? focusable(dialogRef.current)[0] ?? dialogRef.current)?.focus()

    function onKeyDown(e: KeyboardEvent) {
      if (e.key === 'Escape') {
        e.preventDefault()
        onCloseRef.current()
        return
      }
      if (e.key !== 'Tab') return
      const items = focusable(dialogRef.current)
      if (items.length === 0) {
        e.preventDefault()
        return
      }
      const first = items[0]
      const last = items[items.length - 1]
      const active = document.activeElement as HTMLElement | null
      const inside = dialogRef.current?.contains(active)
      if (e.shiftKey) {
        if (active === first || !inside) {
          e.preventDefault()
          last.focus()
        }
      } else if (active === last || !inside) {
        e.preventDefault()
        first.focus()
      }
    }

    document.addEventListener('keydown', onKeyDown, true)
    const prevOverflow = document.body.style.overflow
    document.body.style.overflow = 'hidden'
    return () => {
      document.removeEventListener('keydown', onKeyDown, true)
      document.body.style.overflow = prevOverflow
      prevFocus.current?.focus?.()
    }
  }, [open])

  if (!open) return null

  return createPortal(
    <div
      className="modal-overlay"
      onMouseDown={(e) => {
        if (e.target === e.currentTarget) onClose()
      }}
    >
      <div className={`modal-dialog modal-${size}`} role="dialog" aria-modal="true" aria-label={title} ref={dialogRef} tabIndex={-1}>
        {title && <div className="modal-title">{title}</div>}
        {children}
      </div>
    </div>,
    document.body,
  )
}
