'use client'

import type { FC, PointerEvent as ReactPointerEvent } from 'react'
import type { WorkflowCommentList } from '@/app/components/workflow/comment/types'
import { useAtomValue } from 'jotai'
import { memo, useCallback, useMemo, useRef, useState } from 'react'
import { useReactFlow, useViewport } from 'reactflow'
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
import { userProfileIdAtom } from '@/context/account-state'
import CommentPreview from './comment-preview'

type CommentIconProps = {
  comment: WorkflowCommentList
  onClick: () => void
  isActive?: boolean
  onPositionUpdate?: (position: { x: number; y: number }) => void
}

export const CommentIcon: FC<CommentIconProps> = memo(
  ({ comment, onClick, isActive = false, onPositionUpdate }) => {
    const { flowToScreenPosition, screenToFlowPosition } = useReactFlow()
    const viewport = useViewport()
    const currentUserId = useAtomValue(userProfileIdAtom)
    const isAuthor = comment.created_by_account?.id === currentUserId
    const [showPreview, setShowPreview] = useState(false)
    const [dragPosition, setDragPosition] = useState<{ x: number; y: number } | null>(null)
    const [isDragging, setIsDragging] = useState(false)
    const dragStateRef = useRef<{
      offsetX: number
      offsetY: number
      startX: number
      startY: number
      hasMoved: boolean
    } | null>(null)

    const workflowContainerRect =
      typeof document !== 'undefined'
        ? document.getElementById('workflow-container')?.getBoundingClientRect()
        : null
    const containerLeft = workflowContainerRect?.left ?? 0
    const containerTop = workflowContainerRect?.top ?? 0

    const screenPosition = useMemo(() => {
      return flowToScreenPosition({
        x: comment.position_x,
        y: comment.position_y,
      })
    }, [
      comment.position_x,
      comment.position_y,
      viewport.x,
      viewport.y,
      viewport.zoom,
      flowToScreenPosition,
    ])

    const effectiveScreenPosition = dragPosition ?? screenPosition
    const canvasPosition = useMemo(
      () => ({
        x: effectiveScreenPosition.x - containerLeft,
        y: effectiveScreenPosition.y - containerTop,
      }),
      [effectiveScreenPosition.x, effectiveScreenPosition.y, containerLeft, containerTop],
    )
    const cursorClass = useMemo(() => {
      if (!isAuthor) return 'cursor-pointer'
      if (isActive) return isDragging ? 'cursor-grabbing' : ''
      return isDragging ? 'cursor-grabbing' : 'cursor-pointer'
    }, [isActive, isAuthor, isDragging])

    const handlePointerDown = useCallback(
      (event: ReactPointerEvent<HTMLDivElement>) => {
        if (event.button !== 0) return

        event.stopPropagation()
        event.preventDefault()

        if (!isAuthor) {
          if (event.currentTarget.dataset.role !== 'comment-preview') setShowPreview(false)
          return
        }

        dragStateRef.current = {
          offsetX: event.clientX - screenPosition.x,
          offsetY: event.clientY - screenPosition.y,
          startX: event.clientX,
          startY: event.clientY,
          hasMoved: false,
        }

        setDragPosition(screenPosition)
        setIsDragging(false)

        if (event.currentTarget.dataset.role !== 'comment-preview') setShowPreview(false)

        if (event.currentTarget.setPointerCapture)
          event.currentTarget.setPointerCapture(event.pointerId)
      },
      [isAuthor, screenPosition],
    )

    const handlePointerMove = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {
      const dragState = dragStateRef.current
      if (!dragState) return

      event.stopPropagation()
      event.preventDefault()

      const nextX = event.clientX - dragState.offsetX
      const nextY = event.clientY - dragState.offsetY

      if (!dragState.hasMoved) {
        const distance = Math.hypot(
          event.clientX - dragState.startX,
          event.clientY - dragState.startY,
        )
        if (distance > 4) {
          dragState.hasMoved = true
          setIsDragging(true)
        }
      }

      setDragPosition({ x: nextX, y: nextY })
    }, [])

    const finishDrag = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {
      const dragState = dragStateRef.current
      if (!dragState) return false

      if (event.currentTarget.hasPointerCapture?.(event.pointerId))
        event.currentTarget.releasePointerCapture(event.pointerId)

      dragStateRef.current = null
      setDragPosition(null)
      setIsDragging(false)
      return dragState.hasMoved
    }, [])

    const handlePointerUp = useCallback(
      (event: ReactPointerEvent<HTMLDivElement>) => {
        event.stopPropagation()
        event.preventDefault()

        const finalScreenPosition = dragPosition ?? screenPosition
        const didDrag = finishDrag(event)

        setShowPreview(false)

        if (didDrag) {
          if (onPositionUpdate) {
            const flowPosition = screenToFlowPosition({
              x: finalScreenPosition.x,
              y: finalScreenPosition.y,
            })
            onPositionUpdate(flowPosition)
          }
        } else if (!isActive) {
          onClick()
        }
      },
      [
        dragPosition,
        finishDrag,
        isActive,
        onClick,
        onPositionUpdate,
        screenPosition,
        screenToFlowPosition,
      ],
    )

    const handlePointerCancel = useCallback(
      (event: ReactPointerEvent<HTMLDivElement>) => {
        event.stopPropagation()
        event.preventDefault()
        finishDrag(event)
      },
      [finishDrag],
    )

    const handleMouseEnter = useCallback(() => {
      if (isActive || isDragging) return
      setShowPreview(true)
    }, [isActive, isDragging])

    const handleMouseLeave = useCallback(() => {
      setShowPreview(false)
    }, [])

    const participants = useMemo(() => {
      const list = comment.participants ?? []
      const author = comment.created_by_account
      if (!author) return [...list]
      const rest = list.filter((user) => user.id !== author.id)
      return [author, ...rest]
    }, [comment.created_by_account, comment.participants])

    // Calculate dynamic width based on number of participants
    const participantCount = participants.length
    const maxVisible = Math.min(3, participantCount)
    const showCount = participantCount > 3
    const avatarSize = 24
    const avatarSpacing = 4 // -space-x-1 is about 4px overlap

    // Width calculation: first avatar + (additional avatars * (size - spacing)) + padding
    const dynamicWidth = Math.max(
      40, // minimum width
      8 +
        avatarSize +
        Math.max(0, showCount ? 2 : maxVisible - 1) * (avatarSize - avatarSpacing) +
        8,
    )

    const pointerEventHandlers = useMemo(
      () => ({
        onPointerDown: handlePointerDown,
        onPointerMove: handlePointerMove,
        onPointerUp: handlePointerUp,
        onPointerCancel: handlePointerCancel,
      }),
      [handlePointerCancel, handlePointerDown, handlePointerMove, handlePointerUp],
    )

    return (
      <>
        <div
          className="absolute z-10"
          style={{
            left: canvasPosition.x,
            top: canvasPosition.y,
            transform: 'translate(-50%, -50%)',
          }}
          data-role="comment-marker"
          {...pointerEventHandlers}
        >
          <div
            className={cursorClass}
            onMouseEnter={handleMouseEnter}
            onMouseLeave={handleMouseLeave}
          >
            <div
              className="relative h-10 rounded-t-full rounded-br-full"
              style={{ width: dynamicWidth }}
            >
              <div
                className={`absolute inset-[6px] overflow-hidden rounded-tl-full rounded-tr-full rounded-br-full border bg-components-panel-bg transition-shadow ${
                  isActive
                    ? 'border-primary-500 ring-1 ring-primary-500'
                    : 'border-components-panel-border'
                }`}
              >
                <div className="flex size-full items-center justify-center px-1">
                  <UserAvatarList
                    users={participants}
                    maxVisible={3}
                    size="sm"
                    className="translate-y-[-1.5px]"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* Preview panel */}
        {showPreview && !isActive && (
          <div
            className="absolute z-20"
            style={{
              left: effectiveScreenPosition.x - containerLeft - dynamicWidth / 2,
              top: effectiveScreenPosition.y - containerTop + 20,
              transform: 'translateY(-100%)',
            }}
            data-role="comment-preview"
            {...pointerEventHandlers}
            onMouseEnter={() => setShowPreview(true)}
            onMouseLeave={() => setShowPreview(false)}
          >
            <CommentPreview
              comment={comment}
              onClick={() => {
                setShowPreview(false)
                onClick()
              }}
            />
          </div>
        )}
      </>
    )
  },
  (prevProps, nextProps) => {
    return (
      prevProps.comment.id === nextProps.comment.id &&
      prevProps.comment.position_x === nextProps.comment.position_x &&
      prevProps.comment.position_y === nextProps.comment.position_y &&
      prevProps.onClick === nextProps.onClick &&
      prevProps.isActive === nextProps.isActive &&
      prevProps.onPositionUpdate === nextProps.onPositionUpdate
    )
  },
)

CommentIcon.displayName = 'CommentIcon'
