import {
  useCallback,
  useEffect,
  useState,
} from 'react'
import {
  $createParagraphNode,
  $getSelection,
  $isRangeSelection,
  $setSelection,
  COMMAND_PRIORITY_CRITICAL,
  FORMAT_TEXT_COMMAND,
  SELECTION_CHANGE_COMMAND,
} from 'lexical'
import {
  $getSelectionStyleValueForProperty,
  $patchStyleText,
  $setBlocksType,
} from '@lexical/selection'
import { INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list'
import { mergeRegister } from '@lexical/utils'
import {
  $isLinkNode,
  TOGGLE_LINK_COMMAND,
} from '@lexical/link'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { useNoteEditorStore } from '../store'
import { getSelectedNode } from '../utils'

export const useCommand = () => {
  const [editor] = useLexicalComposerContext()
  const noteEditorStore = useNoteEditorStore()

  const handleCommand = useCallback((type: string) => {
    if (type === 'bold')
      editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')

    if (type === 'italic')
      editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')

    if (type === 'strikethrough')
      editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough')

    if (type === 'link') {
      editor.update(() => {
        const selection = $getSelection()

        if ($isRangeSelection(selection)) {
          const node = getSelectedNode(selection)
          const parent = node.getParent()
          const { setLinkAnchorElement } = noteEditorStore.getState()

          if ($isLinkNode(parent) || $isLinkNode(node)) {
            editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)
            setLinkAnchorElement()
          }
          else {
            editor.dispatchCommand(TOGGLE_LINK_COMMAND, '')
            setLinkAnchorElement(true)
          }
        }
      })
    }

    if (type === 'bullet') {
      const { selectedIsBullet } = noteEditorStore.getState()

      if (selectedIsBullet) {
        editor.update(() => {
          const selection = $getSelection()
          if ($isRangeSelection(selection))
            $setBlocksType(selection, () => $createParagraphNode())
        })
      }
      else {
        editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined)
      }
    }
  }, [editor, noteEditorStore])

  return {
    handleCommand,
  }
}

export const useFontSize = () => {
  const [editor] = useLexicalComposerContext()
  const [fontSize, setFontSize] = useState('12px')
  const [fontSizeSelectorShow, setFontSizeSelectorShow] = useState(false)

  const handleFontSize = useCallback((fontSize: string) => {
    editor.update(() => {
      const selection = $getSelection()

      if ($isRangeSelection(selection))
        $patchStyleText(selection, { 'font-size': fontSize })
    })
  }, [editor])

  const handleOpenFontSizeSelector = useCallback((newFontSizeSelectorShow: boolean) => {
    if (newFontSizeSelectorShow) {
      editor.update(() => {
        const selection = $getSelection()

        if ($isRangeSelection(selection))
          $setSelection(selection.clone())
      })
    }
    setFontSizeSelectorShow(newFontSizeSelectorShow)
  }, [editor])

  useEffect(() => {
    return mergeRegister(
      editor.registerUpdateListener(() => {
        editor.getEditorState().read(() => {
          const selection = $getSelection()

          if ($isRangeSelection(selection)) {
            const fontSize = $getSelectionStyleValueForProperty(selection, 'font-size', '12px')
            setFontSize(fontSize)
          }
        })
      }),
      editor.registerCommand(
        SELECTION_CHANGE_COMMAND,
        () => {
          const selection = $getSelection()

          if ($isRangeSelection(selection)) {
            const fontSize = $getSelectionStyleValueForProperty(selection, 'font-size', '12px')
            setFontSize(fontSize)
          }

          return false
        },
        COMMAND_PRIORITY_CRITICAL,
      ),
    )
  }, [editor])

  return {
    fontSize,
    handleFontSize,
    fontSizeSelectorShow,
    handleOpenFontSizeSelector,
  }
}