'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
  /**
   * Stored separator that should display as a line-break in the editor.
   * When set (e.g. '|'), the stored value "FOO|BAR" is shown as two lines,
   * and newlines typed by the user are serialized back to the separator.
   * Implies `multiline`.
   */
  separator?: string
}

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

  // 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 raw = value ?? ''
    // Convert stored separator to newlines for display.
    const next = separator ? raw.split(separator).join('\n') : raw
    if (el.textContent !== next) el.textContent = next
    el.classList.toggle('rebours-editable--empty', !raw)
  }, [value, separator])

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

  const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
    if (!isMultiline && 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}
    />
  )
}
