import { useTransitionStyles } from '@floating-ui/react'
import {
  autoPlacement,
  autoUpdate,
  offset,
  useFloating,
} from '@floating-ui/react'
import { LinkNode } from '@lexical/link'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { mergeRegister } from '@lexical/utils'
import { $getSelection, $isRangeSelection, $setSelection } from 'lexical'
import { useEffect, useRef, useState } from 'react'
import { colors } from '../../utils/colors.js'
import { shadows } from '../../utils/shadows.js'
import { radius } from '../../utils/radius.js'
import { IconButton } from '../IconButton/index.js'
import { useToast } from '../Toast/index.js'

function FloatingLinkPlugin() {
  const [editor] = useLexicalComposerContext()
  const [open, setOpen] = useState(false)
  const [prevValue, setPrevValue] = useState<string>()
  const [value, setValue] = useState<string>()
  const toast = useToast()

  useEffect(() => {
    function handleKeyDown(event: KeyboardEvent) {
      if (event.key === 'Escape') {
        setOpen(false)
      }
    }

    document.addEventListener('keydown', handleKeyDown)

    return () => {
      document.removeEventListener('keydown', handleKeyDown)
    }
  }, [value, prevValue])

  const { floatingStyles, refs, context, placement } = useFloating({
    open,
    whileElementsMounted: autoUpdate,
    placement: 'bottom-start',
    strategy: 'fixed',
    middleware: [
      offset(8),
      autoPlacement({
        allowedPlacements: [
          'bottom-start',
          'top-start',
          'bottom',
          'top',
          'bottom-end',
          'top-end',
        ],
      }),
    ],
  })
  const { isMounted, styles: transitionStyles } = useTransitionStyles(context, {
    duration: 50,
    initial: {
      transform: `scale(0.9) translateY(${placement.startsWith('top') ? 8 : -8}px`,
      opacity: 0,
    },
    open: {
      opacity: 1,
      transform: `scale(1) translateY(0px)`,
    },
    close: {
      transform: `scale(0.9) translateY(${placement.startsWith('top') ? 8 : -8}px)`,
      opacity: 0,
    },
  })

  useEffect(() => {
    return mergeRegister(
      editor.registerUpdateListener(({ editorState }) => {
        editorState.read(() => {
          const selection = $getSelection()
          if (!$isRangeSelection(selection)) return

          const root = editor.getRootElement()
          const anchor = selection.anchor.getNode()
          const anchorParent = anchor.getParent()
          const native = window.getSelection()

          const node =
            anchor instanceof LinkNode
              ? anchor
              : anchorParent instanceof LinkNode
                ? anchorParent
                : null

          if (node && root.contains(native.anchorNode)) {
            refs.setReference(native.focusNode.parentElement)
            setValue(node.__url)
            setPrevValue(node.__url)
            setOpen(true)

            return
          }

          refs.setReference(null)
          setOpen(false)
          setValue('')
          setPrevValue('')
        })
      }),
    )
  }, [editor, value])

  if (!isMounted) return null

  return (
    <div ref={refs.setFloating} style={{ ...floatingStyles }}>
      <div
        style={{
          background: colors.neutralInverted100,
          border: `1px solid  ${colors.neutral20Adjusted}`,
          boxShadow: shadows.popoverSmall,
          display: 'inline-flex',
          alignItems: 'center',
          borderRadius: radius[16],
          height: 40,
          padding: 8,
          width: 360,
          transitionTimingFunction: 'ease-in-out',
          overflow: 'hidden',
          ...transitionStyles,
        }}
      >
        <div
          style={{
            position: 'absolute',
            inset: 0,
            background: colors.neutral10Background,
            pointerEvents: 'none',
          }}
        />
        <div
          style={{
            position: 'relative',
            display: 'inline-flex',
            justifyContent: 'center',
            alignItems: 'center',
            gap: 4,
            width: '100%',
          }}
        >
          <input
            autoFocus={!value?.length}
            value={value}
            onChange={(e) => {
              setValue(e.target.value)
            }}
            placeholder="Add link"
            style={{
              flex: 1,
              outline: 'none',
              border: 'none',
              background: 'transparent',
              fontSize: 14,
              fontWeight: 400,
              width: '100%',
              height: '100%',
              padding: '0 8px',
              color: colors.neutral80,
            }}
          />
          {value === prevValue ? (
            <>
              {value && (
                <>
                  <IconButton
                    size="small"
                    icon="arrow-out"
                    tooltip="Open in new tab"
                    onClick={() => {
                      window.open(value, '_blank', 'noopener,noreferrer')
                      editor.update(() => {
                        $setSelection(null)
                      })
                      setOpen(false)
                    }}
                  />
                  <IconButton
                    size="small"
                    icon="copy"
                    tooltip="Copy link"
                    onClick={() => {
                      navigator.clipboard.writeText(value)
                      toast('Link copied', { icon: 'copy' })
                      editor.update(() => {
                        $setSelection(null)
                      })
                      setOpen(false)
                    }}
                  />
                </>
              )}
              <div
                style={{
                  margin: '0 4px',
                  width: 1,
                  height: 16,
                  background: colors.neutral20Adjusted,
                }}
              />
              <IconButton
                size="small"
                icon="link-off"
                tooltip="Remove link"
                onClick={() => {
                  editor.update(() => {
                    const selection = $getSelection()
                    if (!$isRangeSelection(selection)) return

                    const nodes = selection.extract()
                    nodes.forEach((node) => {
                      const parent = node.getParent()
                      if (parent instanceof LinkNode) {
                        const children = parent.getChildren()
                        for (let i = 0; i < children.length; i++) {
                          parent.insertBefore(children[i])
                        }
                        parent.remove()
                      }
                    })
                  })
                }}
              />
            </>
          ) : (
            <>
              <IconButton
                size="small"
                icon="checkmark"
                tooltip="Save changes"
                keyHint="Enter"
                onClick={() => {
                  editor.update(
                    () => {
                      const selection = $getSelection()
                      if (!$isRangeSelection(selection)) return
                      const nodes = selection.extract()
                      nodes.forEach((node) => {
                        const parent = node.getParent()
                        if (parent instanceof LinkNode) {
                          parent.setURL(value)
                        }
                      })
                      nodes[nodes.length - 1].selectEnd()
                    },
                    {
                      onUpdate: () => {
                        setOpen(false)
                      },
                    },
                  )
                }}
              />
              <IconButton
                size="small"
                icon="close"
                tooltip="Discard changes"
                keyHint="Esc"
                keyHintVisualOnly
                onClick={() => {
                  setOpen(false)
                }}
              />
            </>
          )}
        </div>
      </div>
    </div>
  )
}

export { FloatingLinkPlugin }
