import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { $createTextNode, $getSelection, $insertNodes, $setSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'
import { $wrapNodeInElement, mergeRegister } from '@lexical/utils'
import { $createLinkNode, $isLinkNode } from '@lexical/link'
import { Modal } from 'react-bootstrap'
import React, { useState, useCallback, useContext, useRef, useEffect } from 'react'
import { Form, Input, SubmitButton } from '../../components/form'
import { ensureProtocol } from '../../lib/url'
import { getSelectedNode } from '../utils/selected-node'
import { namedUrlSchema } from '../../lib/validate'

export const INSERT_LINK_COMMAND = createCommand('INSERT_LINK_COMMAND')

export default function LinkInsertPlugin () {
  const [editor] = useLexicalComposerContext()

  useEffect(() => {
    return mergeRegister(
      editor.registerCommand(
        INSERT_LINK_COMMAND,
        (payload) => {
          const selection = $getSelection()
          const node = getSelectedNode(selection)
          const parent = node.getParent()
          if ($isLinkNode(parent)) {
            parent.remove()
          } else if ($isLinkNode(node)) {
            node.remove()
          }
          const textNode = $createTextNode(payload.text)
          $insertNodes([textNode])
          const linkNode = $createLinkNode(payload.url)
          $wrapNodeInElement(textNode, () => linkNode)
          $setSelection(textNode.select())
          return true
        },
        COMMAND_PRIORITY_EDITOR
      )
    )
  }, [editor])

  return null
}

export const LinkInsertContext = React.createContext({
  link: null,
  setLink: () => {}
})

export function LinkInsertProvider ({ children }) {
  const [link, setLink] = useState(null)

  const contextValue = {
    link,
    setLink: useCallback(link => setLink(link), [])
  }

  return (
    <LinkInsertContext.Provider value={contextValue}>
      <LinkInsertModal />
      {children}
    </LinkInsertContext.Provider>
  )
}

export function useLinkInsert () {
  const { link, setLink } = useContext(LinkInsertContext)
  return { link, setLink }
}

export function LinkInsertModal () {
  const [editor] = useLexicalComposerContext()
  const { link, setLink } = useLinkInsert()
  const inputRef = useRef(null)

  useEffect(() => {
    if (link) {
      inputRef.current?.focus()
    }
  }, [link])

  return (
    <Modal
      show={!!link}
      onHide={() => {
        setLink(null)
        setTimeout(() => editor.focus(), 100)
      }}
    >
      <div
        className='modal-close' onClick={() => {
          setLink(null)
          // I think bootstrap messes with the focus on close so we have to do this ourselves
          setTimeout(() => editor.focus(), 100)
        }}
      >X
      </div>
      <Modal.Body>
        <Form
          initial={{
            text: link?.text,
            url: link?.url
          }}
          schema={namedUrlSchema}
          onSubmit={async ({ text, url }) => {
            editor.dispatchCommand(INSERT_LINK_COMMAND, { url: ensureProtocol(url), text })
            await setLink(null)
            setTimeout(() => editor.focus(), 100)
          }}
        >
          <Input
            label='text'
            name='text'
            innerRef={inputRef}
            required
          />
          <Input
            label='url'
            name='url'
            required
          />
          <div className='d-flex'>
            <SubmitButton variant='success' className='ml-auto mt-1 px-4'>ok</SubmitButton>
          </div>
        </Form>
      </Modal.Body>
    </Modal>
  )
}