import React, {
  forwardRef,
  useImperativeHandle,
  useRef,
  useEffect,
  useState,
} from 'react'
import { cn } from '@/utils/cn'
import type { MarkWithMetadata } from './image-redraw-editor'

export interface InlineMarkEditorRef {
  insertMark: (mark: MarkWithMetadata) => void
  focus: () => void
}

export interface InlineMarkEditorProps {
  className?: string
  placeholder?: string
  initialHtml?: string
  onChange?: (val: string, marks: MarkWithMetadata[], html: string) => void
  onEnter?: (e: React.KeyboardEvent | React.MouseEvent) => void
}

export const InlineMarkEditor = forwardRef<
  InlineMarkEditorRef,
  InlineMarkEditorProps
>((props, ref) => {
  const { className, placeholder, initialHtml, onChange, onEnter } = props
  const editorRef = useRef<HTMLDivElement>(null)
  const [isEmpty, setIsEmpty] = useState(!initialHtml || initialHtml === '<br>')

  useEffect(() => {
    if (
      editorRef.current &&
      initialHtml &&
      editorRef.current.innerHTML === ''
    ) {
      editorRef.current.innerHTML = initialHtml
      setIsEmpty(initialHtml === '' || initialHtml === '<br>')
    }
  }, [initialHtml])

  const notifyChange = () => {
    if (!editorRef.current) return
    const root = editorRef.current
    let val = ''
    const newMarks: MarkWithMetadata[] = []

    // 递归遍历 DOM，提取文本和标记
    const traverse = (node: Node) => {
      if (node.nodeType === Node.TEXT_NODE) {
        // 处理无宽空格和普通文本
        val += (node.textContent || '').replace(/\u200B/g, '')
      } else if (node.nodeType === Node.ELEMENT_NODE) {
        const el = node as HTMLElement
        if (el.tagName === 'BR') {
          val += '\n'
        } else if (el.dataset.mark) {
          try {
            const markObj = JSON.parse(
              decodeURIComponent(el.dataset.mark),
            ) as MarkWithMetadata
            newMarks.push(markObj)
            const { index, x, y, width, height, elementName, elementType } =
              markObj
            val += `[@image-mark:#${index},@rect:${Math.round(x || 0)},${Math.round(
              y || 0,
            )},${Math.round(width || 0)},${Math.round(height || 0)},@element:${
              elementName || 'undefined'
            },@type:${elementType || 'undefined'}]`
          } catch (e) {
            // ignore
          }
        } else {
          // 对于非内联块元素，处理换行逻辑
          if (el.tagName === 'DIV' || el.tagName === 'P') {
            if (val.length > 0 && !val.endsWith('\n')) val += '\n'
          }
          Array.from(node.childNodes).forEach(traverse)
        }
      }
    }
    Array.from(root.childNodes).forEach(traverse)

    const textIsEmpty = root.innerText.replace(/\u200B/g, '').trim() === ''
    const marksIsEmpty = root.querySelectorAll('[data-mark]').length === 0
    setIsEmpty(textIsEmpty && marksIsEmpty)

    onChange?.(val, newMarks, root.innerHTML)
  }

  useImperativeHandle(ref, () => ({
    insertMark: (mark: MarkWithMetadata) => {
      const editor = editorRef.current
      if (!editor) return

      editor.focus()
      const selection = window.getSelection()
      let range: Range

      if (selection && selection.rangeCount > 0) {
        range = selection.getRangeAt(0)
        // 确保光标在编辑器内部
        if (!editor.contains(range.commonAncestorContainer)) {
          range = document.createRange()
          range.selectNodeContents(editor)
          range.collapse(false) // 移到末尾
        }
      } else {
        range = document.createRange()
        range.selectNodeContents(editor)
        range.collapse(false)
      }

      const markSpan = document.createElement('span')
      markSpan.contentEditable = 'false'
      markSpan.className =
        'pe-image-mark mx-[2px] inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold select-none cursor-default align-middle'
      markSpan.style.width = '20px'
      markSpan.style.height = '20px'
      markSpan.style.fontSize = '12px'
      markSpan.dataset.mark = encodeURIComponent(JSON.stringify(mark))
      markSpan.dataset.index = mark.index.toString()
      markSpan.innerText = mark.index.toString()

      range.deleteContents()
      range.insertNode(markSpan)

      // 插入零宽空格以便于继续输入
      const spaceNode = document.createTextNode('\u200B')
      range.setEndAfter(markSpan)
      range.collapse(false)
      range.insertNode(spaceNode)

      range.setStartAfter(spaceNode)
      range.collapse(true)

      selection?.removeAllRanges()
      selection?.addRange(range)

      notifyChange()
    },
    focus: () => {
      editorRef.current?.focus()
    },
  }))

  const handleInput = () => {
    notifyChange()
  }

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault()
      onEnter?.(e)
    } else if (e.key === 'Backspace') {
      // 处理零宽空格和删除问题
      const selection = window.getSelection()
      if (selection && selection.rangeCount > 0) {
        const range = selection.getRangeAt(0)
        if (range.collapsed) {
          const pre = range.startContainer.textContent?.substring(
            0,
            range.startOffset,
          )
          if (pre?.endsWith('\u200B')) {
            // 光标前是零宽空格
            range.setStart(range.startContainer, range.startOffset - 1)
            range.deleteContents()
          }
        }
      }
    }
    setTimeout(notifyChange, 0)
  }

  return (
    <div
      className={cn('relative cursor-text flex items-center', className)}
      onClick={() => {
        if (editorRef.current && document.activeElement !== editorRef.current) {
          editorRef.current.focus()
          const selection = window.getSelection()
          const range = document.createRange()
          range.selectNodeContents(editorRef.current)
          range.collapse(false)
          selection?.removeAllRanges()
          selection?.addRange(range)
        }
      }}
    >
      {isEmpty && placeholder && (
        <div className='absolute top-1/2 -translate-y-1/2 left-[8px] text-gray-400 pointer-events-none select-none text-[14px]'>
          {placeholder}
        </div>
      )}
      <div
        ref={editorRef}
        contentEditable
        className='outline-none font-normal text-[14px] whitespace-pre-wrap break-words min-h-[24px] w-full max-h-[180px] overflow-y-auto px-[8px] py-[4px] leading-relaxed text-[var(--text-main,inherit)]'
        onInput={handleInput}
        onKeyDown={handleKeyDown}
        onBlur={handleInput}
      />
    </div>
  )
})

InlineMarkEditor.displayName = 'InlineMarkEditor'
