'use client'

import { useField } from '@payloadcms/ui'
import { useLayoutEffect, useRef } from 'react'

type Props = {
  path: string
  as?: 'span' | 'h2' | 'p' | 'div'
  className?: string
  multiline?: boolean
  placeholder?: string
}

export function InlineEditable({ path, as: Tag = 'span', className, multiline, placeholder }: Props) {
  const { value, setValue } = useField<string>({ path })
  const ref = useRef<HTMLElement | null>(null)

  // Sync textContent from value. React doesn't reconcile children of
  // contentEditable elements, so we drive the DOM imperatively — and
  // never clobber the DOM while the user is actively typing in it.
  useLayoutEffect(() => {
    const el = ref.current
    if (!el) return
    if (typeof document !== 'undefined' && document.activeElement === el) return
    const next = value ?? ''
    if (el.textContent !== next) el.textContent = next
    el.classList.toggle('rebours-editable--empty', !value)
  }, [value])

  const commit = (e: React.FocusEvent<HTMLElement>) => {
    const next = (e.currentTarget.textContent ?? '').replace(/\u00A0/g, ' ')
    if (next !== (value ?? '')) setValue(next)
    e.currentTarget.classList.toggle('rebours-editable--empty', !next)
  }

  const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
    if (!multiline && e.key === 'Enter') {
      e.preventDefault()
      ;(e.currentTarget as HTMLElement).blur()
    }
  }

  const onPaste = (e: React.ClipboardEvent<HTMLElement>) => {
    e.preventDefault()
    const text = e.clipboardData.getData('text/plain')
    document.execCommand('insertText', false, text)
  }

  return (
    <Tag
      ref={ref as never}
      className={`rebours-editable${className ? ' ' + className : ''}`}
      contentEditable
      suppressContentEditableWarning
      spellCheck={false}
      onBlur={commit}
      onKeyDown={onKeyDown}
      onPaste={onPaste}
      data-placeholder={placeholder ?? ''}
      data-as={Tag}
    />
  )
}
