import { useRef, useEffect, KeyboardEvent, useState } from 'react'

interface TextInputProps {
  value: string
  onInput: (value: string) => void
  onKeyDown: (e: TextInputKeyDownEvent) => void
  className?: string
  placeholder?: string
}

export interface TextInputKeyDownEvent {
  key: string
  ctrlKey: boolean
  preventDefault: () => void
}

export default function FancyTextEditor({
  value: _value,
  onInput,
  onKeyDown,
  className: extraClasses = '',
  placeholder = '',
}: TextInputProps) {
  const divRef = useRef<HTMLDivElement>(null)
  const [hasFocus, setHasFocus] = useState(false)

  // the contenteditable likes to slip in newlines at the bottom of our innerText
  // which makes it bad to check for empty string because it might be "\n"
  // so we just trim it upfront and then fogeddaboudit
  const value = _value.trim()

  // The funky mechanics here are to stop the cursor from jumping back the start.
  // It probably will have the cursor jump to the start if anything changes programmatically,
  // which is probably unnecessary anyway
  useEffect(() => {
    const div = divRef.current
    if (div == null) {
      return
    }

    if (!value && !hasFocus) {
      div.innerText = placeholder
    } else if (div.innerText !== value) {
      div.innerText = value
    }
  }, [hasFocus, placeholder, value])

  useEffect(() => {
    const div = divRef.current!
    if (div == null) {
      return
    }

    const inputListener = () => {
      onInput(div.innerText)
    }

    const blurListener = () => {
      setHasFocus(false)
      if (!value) {
        div.innerText = placeholder
      }
    }

    const focusListener = () => {
      setHasFocus(true)
      div.innerText = value
    }

    div.addEventListener('input', inputListener)
    div.addEventListener('blur', blurListener)
    div.addEventListener('focus', focusListener)

    return () => {
      div.removeEventListener('focus', focusListener)
      div.removeEventListener('blur', blurListener)
      div.removeEventListener('input', inputListener)
    }
  }, [onInput, placeholder, value])

  const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
    onKeyDown(e)
  }

  const textColour = value ? 'text-gray-900' : 'text-gray-500'
  return (
    <div
      ref={divRef}
      className={`text-input w-full min-h-30 ${textColour} ${extraClasses}`}
      contentEditable
      onKeyDown={handleKeyDown}
      suppressContentEditableWarning
    ></div>
  )
}
