import {
  EditablePreview,
  EditableInput,
  Editable,
  useEventListener,
  Flex,
  Fade,
  IconButton,
} from '@chakra-ui/react'
import { PlusIcon } from 'assets/icons'
import { ContextMenu } from 'components/shared/ContextMenu'
import { Coordinates } from 'contexts/GraphContext'
import { useTypebot } from 'contexts/TypebotContext'
import { ChoiceInputStep, ChoiceItem } from 'models'
import React, { useState } from 'react'
import { isDefined, isSingleChoiceInput } from 'utils'
import { SourceEndpoint } from '../SourceEndpoint'
import { ChoiceItemNodeContextMenu } from './ChoiceItemNodeContextMenu'

type ChoiceItemNodeProps = {
  item: ChoiceItem
  onMouseMoveBottomOfElement?: () => void
  onMouseMoveTopOfElement?: () => void
  onMouseDown?: (
    stepNodePosition: { absolute: Coordinates; relative: Coordinates },
    item: ChoiceItem
  ) => void
}

export const ChoiceItemNode = ({
  item,
  onMouseDown,
  onMouseMoveBottomOfElement,
  onMouseMoveTopOfElement,
}: ChoiceItemNodeProps) => {
  const { deleteChoiceItem, updateChoiceItem, typebot, createChoiceItem } =
    useTypebot()
  const [mouseDownEvent, setMouseDownEvent] =
    useState<{ absolute: Coordinates; relative: Coordinates }>()
  const [isMouseOver, setIsMouseOver] = useState(false)

  const handleMouseDown = (e: React.MouseEvent) => {
    if (!onMouseDown) return
    e.stopPropagation()
    const element = e.currentTarget as HTMLDivElement
    const rect = element.getBoundingClientRect()
    const relativeX = e.clientX - rect.left
    const relativeY = e.clientY - rect.top
    setMouseDownEvent({
      absolute: { x: e.clientX + relativeX, y: e.clientY + relativeY },
      relative: { x: relativeX, y: relativeY },
    })
  }

  const handleGlobalMouseUp = () => {
    setMouseDownEvent(undefined)
  }
  useEventListener('mouseup', handleGlobalMouseUp)

  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
    if (!onMouseMoveBottomOfElement || !onMouseMoveTopOfElement) return
    const isMovingAndIsMouseDown =
      mouseDownEvent &&
      onMouseDown &&
      (event.movementX > 0 || event.movementY > 0)
    if (isMovingAndIsMouseDown) {
      onMouseDown(mouseDownEvent, item)
      deleteChoiceItem(item.id)
      setMouseDownEvent(undefined)
    }
    const element = event.currentTarget as HTMLDivElement
    const rect = element.getBoundingClientRect()
    const y = event.clientY - rect.top
    if (y > rect.height / 2) onMouseMoveBottomOfElement()
    else onMouseMoveTopOfElement()
  }

  const handleInputSubmit = (content: string) =>
    updateChoiceItem(item.id, { content: content === '' ? undefined : content })

  const handlePlusClick = () => {
    const nextIndex =
      (
        typebot?.steps.byId[item.stepId] as ChoiceInputStep
      ).options.itemIds.indexOf(item.id) + 1
    createChoiceItem({ stepId: item.stepId }, nextIndex)
  }

  const handleMouseEnter = () => setIsMouseOver(true)
  const handleMouseLeave = () => setIsMouseOver(false)
  return (
    <ContextMenu<HTMLDivElement>
      renderMenu={() => <ChoiceItemNodeContextMenu itemId={item.id} />}
    >
      {(ref, isOpened) => (
        <Flex
          align="center"
          pos="relative"
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
          justifyContent="center"
        >
          <Editable
            ref={ref}
            px="4"
            py="2"
            rounded="md"
            bgColor="green.200"
            borderWidth="2px"
            borderColor={isOpened ? 'blue.400' : 'gray.400'}
            defaultValue={item.content ?? 'Click to edit'}
            flex="1"
            startWithEditView={!isDefined(item.content)}
            onSubmit={handleInputSubmit}
            onMouseDown={handleMouseDown}
            onMouseMove={handleMouseMove}
          >
            <EditablePreview />
            <EditableInput />
          </Editable>
          {typebot && isSingleChoiceInput(typebot.steps.byId[item.stepId]) && (
            <SourceEndpoint
              source={{
                blockId: typebot.steps.byId[item.stepId].blockId,
                stepId: item.stepId,
                choiceItemId: item.id,
              }}
              pos="absolute"
              right="15px"
            />
          )}
          <Fade
            in={isMouseOver}
            style={{ position: 'absolute', bottom: '-15px', zIndex: 3 }}
            unmountOnExit
          >
            <IconButton
              aria-label="Add item"
              icon={<PlusIcon />}
              size="xs"
              onClick={handlePlusClick}
            />
          </Fade>
        </Flex>
      )}
    </ContextMenu>
  )
}
