'use client'

import * as React from 'react'
import type { AdminMedia } from '@admin/types'
import type { NodeViewProps } from '@tiptap/react'
import { MediaGalleryDialog } from '@admin/components/shared/media/media-gallery-dialog'
import { Button } from '@admin/components/ui/button'
import { focusNextNode } from '@admin/utils/editor/focus-next-node'
import { getMediaLabel } from '@admin/utils/editor/get-media-label'
import { getNumberAttr } from '@admin/utils/editor/get-number-attr'
import { getStringAttr } from '@admin/utils/editor/get-string-attr'
import { isValidPosition } from '@admin/utils/editor/is-valid-position'
import { cn } from '@admin/utils/shared/cn'
import { NodeViewWrapper } from '@tiptap/react'
import NextImage from 'next/image'

export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
  const { editor, node } = props
  const src = getStringAttr(node.attrs.src)
  const alt = getStringAttr(node.attrs.alt)
  const title = getStringAttr(node.attrs.title)
  const width = getNumberAttr(node.attrs.width)
  const height = getNumberAttr(node.attrs.height)
  const aspectRatio = width && height ? `${width} / ${height}` : '16 / 9'
  const [isDialogOpen, setIsDialogOpen] = React.useState(false)
  const [isControlsVisible, setIsControlsVisible] = React.useState(false)

  const handleChangeClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault()
    event.stopPropagation()
    setIsDialogOpen(true)
  }, [])

  const handleMediaSelected = React.useCallback(
    (selected: AdminMedia | AdminMedia[]) => {
      const item = Array.isArray(selected) ? selected[0] : selected
      const pos = props.getPos()
      if (!item?.url || !isValidPosition(pos)) return

      const label = item.alt || getMediaLabel(item.url)
      editor.view.dispatch(
        editor.state.tr.setNodeMarkup(pos, undefined, {
          ...node.attrs,
          src: item.url,
          alt: label,
          title: item.filename || label,
          width: item.width ?? null,
          height: item.height ?? null
        })
      )
      editor.commands.focus()
    },
    [editor, node.attrs, props]
  )

  const handleImageLoad = React.useCallback(
    (event: React.SyntheticEvent<HTMLImageElement>) => {
      if (width && height) return
      const image = event.currentTarget
      if (!image.naturalWidth || !image.naturalHeight) return
      const pos = props.getPos()
      if (!isValidPosition(pos)) return
      const tr = editor.state.tr
        .setNodeMarkup(pos, undefined, {
          ...node.attrs,
          width: image.naturalWidth,
          height: image.naturalHeight
        })
        .setMeta('addToHistory', false)
      editor.view.dispatch(tr)
    },
    [editor, height, node.attrs, props, width]
  )

  const handleRemove = React.useCallback(
    (event: React.MouseEvent<HTMLButtonElement>) => {
      event.preventDefault()
      event.stopPropagation()

      const pos = props.getPos()
      if (!isValidPosition(pos)) return

      editor
        .chain()
        .focus()
        .deleteRange({ from: pos, to: pos + node.nodeSize })
        .run()
      focusNextNode(editor)
    },
    [editor, node.nodeSize, props]
  )

  return (
    <NodeViewWrapper
      className="not-prose relative my-4 block max-w-full rounded-md"
      contentEditable={false}
      data-content-editor-image-node=""
      onMouseEnter={() => setIsControlsVisible(true)}
      onMouseMove={() => setIsControlsVisible(true)}
      onMouseOver={() => setIsControlsVisible(true)}
      onMouseLeave={() => setIsControlsVisible(false)}
      onFocusCapture={() => setIsControlsVisible(true)}
      onBlurCapture={(event: React.FocusEvent<HTMLDivElement>) => {
        if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {
          setIsControlsVisible(false)
        }
      }}
      tabIndex={0}
      style={{ width: width ? `${width}px` : '100%' }}
    >
      <div
        className="relative max-w-full overflow-hidden rounded-md bg-muted/20"
        style={{ aspectRatio }}
      >
        {src && (
          <NextImage
            src={src}
            alt={alt}
            title={title || undefined}
            fill
            sizes="768px"
            unoptimized
            className="!m-0 !h-full !w-full !max-w-full object-contain"
            onLoad={handleImageLoad}
          />
        )}
        {editor.isEditable && (
          <div
            data-content-editor-image-controls-overlay=""
            className={cn(
              'pointer-events-none absolute inset-0 flex items-center justify-center gap-1 rounded-md bg-black/10 backdrop-blur-xs transition-opacity duration-200 ease-out',
              {
                'opacity-100': isControlsVisible,
                'opacity-0': !isControlsVisible
              }
            )}
          >
            <Button
              type="button"
              variant="outline"
              onMouseDown={(event) => event.preventDefault()}
              onClick={handleChangeClick}
              className="pointer-events-auto border-primary/10"
            >
              Change
            </Button>
            <Button
              type="button"
              variant="default"
              onMouseDown={(event) => event.preventDefault()}
              onClick={handleRemove}
              className="pointer-events-auto"
            >
              Remove
            </Button>
          </div>
        )}
      </div>
      {editor.isEditable && (
        <MediaGalleryDialog
          open={isDialogOpen}
          onOpenChange={setIsDialogOpen}
          onSelect={handleMediaSelected}
          mode="single"
          accept="image/*"
        />
      )}
    </NodeViewWrapper>
  )
}
