import BN from 'bn.js'
import { format } from 'date-fns'
import { FC, useCallback, useEffect, useRef, useState } from 'react'
import { CSSTransition, SwitchTransition } from 'react-transition-group'

import { BasicMembershipFieldsFragment } from '@/api/queries/__generated__/fragments.generated'
import { SvgActionChevronB, SvgActionChevronT, SvgActionEdit, SvgActionMore, SvgActionTrash } from '@/assets/icons'
import { AvatarGroupUrlAvatar } from '@/components/Avatar/AvatarGroup'
import { Text } from '@/components/Text'
import { Tooltip } from '@/components/Tooltip'
import { TextButton } from '@/components/_buttons/Button'
import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
import { ContextMenu } from '@/components/_overlays/ContextMenu'
import { PopoverImperativeHandle } from '@/components/_overlays/Popover'
import { ReactionsOnboardingPopover } from '@/components/_video/ReactionsOnboardingPopover'
import { atlasConfig } from '@/config'
import { absoluteRoutes } from '@/config/routes'
import { useTouchDevice } from '@/hooks/useTouchDevice'
import { CommentReaction } from '@/joystream-lib/types'
import { useMemberAvatar } from '@/providers/assets/assets.hooks'
import { cVar, transitions } from '@/styles'
import { formatDate, formatDateAgo } from '@/utils/time'

import {
  CommentArticle,
  CommentFooter,
  CommentHeader,
  CommentHeaderDot,
  CommentWrapper,
  DeletedComment,
  HighlightableText,
  KebabMenuIconButton,
  ReactionsAndPopover,
  ReactionsWrapper,
  RepliesWrapper,
  ReplyButton,
  StyledAvatarGroup,
  StyledFooterSkeletonLoader,
  StyledLink,
  StyledSvgActionTrash,
} from './Comment.styles'

import { CommentBody } from '../CommentBody'
import { CommentRow, CommentRowProps } from '../CommentRow'
import { ReactionChip, ReactionChipProps } from '../ReactionChip'
import { ReactionPopover } from '../ReactionPopover'

export type InternalCommentProps = {
  author: BasicMembershipFieldsFragment | undefined
  memberHandle: string | undefined
  createdAt: Date | undefined
  text: string | undefined
  loading: boolean | undefined
  isEdited: boolean | undefined
  isAbleToEdit: boolean | undefined
  isModerated: boolean | undefined
  type: 'default' | 'deleted' | 'options' | 'processing'
  reactions: Omit<ReactionChipProps, 'onReactionClick'>[] | undefined
  reactionPopoverDismissed: boolean | undefined
  replyAvatars?: (AvatarGroupUrlAvatar & { handle: string })[]
  repliesOpen: boolean | undefined
  repliesCount: number | undefined
  isCommentFromUrl: boolean | undefined
  videoId: string | undefined
  commentId: string | undefined
  reactionFee: BN | undefined
  onEditedLabelClick: (() => void) | undefined
  onEditClick: (() => void) | undefined
  onDeleteClick: (() => void) | undefined
  onReplyClick: (() => void) | undefined
  onToggleReplies: (() => void) | undefined
  onReactionClick: ((reaction: CommentReaction) => void) | undefined
  onOnBoardingPopoverOpen: ((reaction: CommentReaction) => Promise<void>) | undefined
} & Pick<CommentRowProps, 'highlighted' | 'indented' | 'memberUrl'>

export const InternalComment: FC<InternalCommentProps> = ({
  indented,
  highlighted,
  author,
  memberUrl,
  memberHandle,
  text,
  createdAt,
  type,
  loading,
  isEdited,
  isModerated,
  isAbleToEdit,
  reactionPopoverDismissed,
  reactionFee,
  onEditedLabelClick,
  onEditClick,
  onDeleteClick,
  onReactionClick,
  onOnBoardingPopoverOpen,
  reactions,
  onReplyClick,
  replyAvatars,
  onToggleReplies,
  repliesOpen,
  repliesCount,
  isCommentFromUrl,
  videoId,
  commentId,
}) => {
  const [commentHover, setCommentHover] = useState(false)
  // tempReactionId is used to show processing state on the reaction when the onboarding popover is opened for it
  const [tempReactionId, setTempReactionId] = useState<CommentReaction | null>(null)
  const isDeleted = type === 'deleted'
  const isProcessing = type === 'processing'
  const shouldShowKebabButton = type === 'options' && !loading && !isDeleted

  const popoverRef = useRef<PopoverImperativeHandle>(null)
  const isTouchDevice = useTouchDevice()
  const { url: memberAvatarUrl, isLoadingAsset: isMemberAvatarLoading } = useMemberAvatar(author)
  const filteredDuplicatedAvatars = repliesCount
    ? replyAvatars
      ? [...new Map(replyAvatars?.map((item) => [item.handle, item])).values()]
      : Array.from({ length: repliesCount }, () => ({ url: undefined }))
    : []

  const tooltipDate = createdAt ? `${formatDate(createdAt || new Date())} at ${format(createdAt, 'HH:mm')}` : undefined

  const contexMenuItems = [
    ...(isAbleToEdit
      ? [
          {
            nodeStart: <SvgActionEdit />,
            onClick: onEditClick,
            label: 'Edit',
          },
        ]
      : []),
    {
      nodeStart: <SvgActionTrash />,
      onClick: onDeleteClick,
      label: 'Delete',
      destructive: true,
    },
  ]

  const domRef = useRef<HTMLDivElement>(null)
  const [highlightedPreviously, setHighlightedPreviously] = useState<boolean | undefined>(false)

  // scroll comment into view once the comment gets highlighted
  useEffect(() => {
    if (highlighted === true && !highlightedPreviously && !isCommentFromUrl) {
      domRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })
    }
    setHighlightedPreviously(highlighted)
  }, [highlightedPreviously, highlighted, isCommentFromUrl])

  const isSomeReactionDisabled = reactions?.some(({ state }) => state === 'disabled')

  const allReactionsApplied =
    reactions && reactions.filter((r) => r.count).length >= atlasConfig.features.comments.reactions.length

  const handleOnboardingPopoverHide = useCallback(() => {
    popoverRef.current?.hide()
    setTempReactionId(null)
  }, [])

  const handleCommentReactionClick = useCallback(
    async (reactionId: CommentReaction) => {
      if (!reactionPopoverDismissed) {
        setTempReactionId(reactionId)
        await onOnBoardingPopoverOpen?.(reactionId)
        popoverRef.current?.show()
      } else {
        onReactionClick?.(reactionId)
      }
    },
    [onOnBoardingPopoverOpen, onReactionClick, reactionPopoverDismissed]
  )

  const sortedReactions = reactions && [...reactions].sort((a, b) => (b.count || 0) - (a.count || 0))
  const hasReactionsAndCommentIsNotDeleted = isDeleted ? !!sortedReactions?.find((r) => r.count) : true
  return (
    <CommentRow
      processing={type === 'processing'}
      indented={indented}
      highlighted={highlighted}
      isMemberAvatarLoading={loading || isMemberAvatarLoading}
      memberUrl={memberUrl}
      memberAvatarUrl={memberAvatarUrl}
      onMouseEnter={() => setCommentHover(true)}
      onMouseLeave={() => setCommentHover(false)}
    >
      <CommentWrapper shouldShowKebabButton={shouldShowKebabButton} ref={domRef}>
        <SwitchTransition>
          <CSSTransition
            timeout={parseInt(cVar('animationTimingFast', true))}
            key={loading?.toString()}
            classNames={transitions.names.fade}
          >
            <CommentArticle isDeleted={isDeleted}>
              {loading ? (
                <>
                  <SkeletonLoader width={128} height={20} />
                  <SkeletonLoader width="100%" height={16} />
                  <SkeletonLoader width="70%" height={16} />
                </>
              ) : (
                <>
                  <CommentHeader>
                    <StyledLink to={memberUrl || ''} isProcessing={isProcessing}>
                      <Text as="span" variant="h200" margin={{ right: 2 }}>
                        {memberHandle}
                      </Text>
                    </StyledLink>
                    <CommentHeaderDot />
                    <Tooltip text={tooltipDate} placement="top" offsetY={4} delay={[1000, null]}>
                      <StyledLink
                        to={absoluteRoutes.viewer.video(videoId, { commentId })}
                        isProcessing={isProcessing}
                        onClick={(e) => e.preventDefault()}
                      >
                        <HighlightableText as="span" variant="t200" color="colorText" margin={{ left: 2, right: 2 }}>
                          {formatDateAgo(createdAt || new Date())}
                        </HighlightableText>
                      </StyledLink>
                    </Tooltip>
                    {isEdited && !isDeleted && (
                      <>
                        <CommentHeaderDot />
                        <HighlightableText
                          as="span"
                          variant="t200"
                          color="colorText"
                          margin={{ left: 2 }}
                          onClick={onEditedLabelClick}
                        >
                          edited
                        </HighlightableText>
                      </>
                    )}
                  </CommentHeader>
                  {isDeleted ? (
                    <DeletedComment as="span" variant="t200" color="colorTextMuted">
                      <StyledSvgActionTrash /> Comment deleted by {isModerated ? 'channel owner' : 'author'}
                    </DeletedComment>
                  ) : (
                    <CommentBody>{text}</CommentBody>
                  )}
                </>
              )}
              <CommentFooter isProcessing={isProcessing}>
                {loading ? (
                  <ReactionsAndPopover>
                    <StyledFooterSkeletonLoader width={48} height={32} rounded />
                    <StyledFooterSkeletonLoader width={48} height={32} rounded />
                  </ReactionsAndPopover>
                ) : (
                  <ReactionsOnboardingPopover
                    ref={popoverRef}
                    fee={reactionFee}
                    onConfirm={() => {
                      tempReactionId && onReactionClick?.(tempReactionId)
                      handleOnboardingPopoverHide()
                    }}
                    onDecline={handleOnboardingPopoverHide}
                    trigger={
                      <ReactionsWrapper>
                        {hasReactionsAndCommentIsNotDeleted && (
                          <ReactionsAndPopover>
                            {sortedReactions?.map(({ reactionId, active, count, state }) => (
                              <ReactionChip
                                key={reactionId}
                                reactionId={reactionId}
                                active={active}
                                count={count}
                                state={tempReactionId === reactionId ? 'processing' : state}
                                onReactionClick={handleCommentReactionClick}
                              />
                            ))}
                            {!allReactionsApplied && !isDeleted && (
                              <ReactionPopover
                                disabled={isSomeReactionDisabled}
                                onReactionClick={handleCommentReactionClick}
                              />
                            )}
                          </ReactionsAndPopover>
                        )}
                        <RepliesWrapper>
                          {!!repliesCount && filteredDuplicatedAvatars.length ? (
                            <StyledAvatarGroup
                              size="small"
                              avatarStrokeColor={highlighted ? cVar('colorBackground', true) : undefined}
                              avatars={filteredDuplicatedAvatars}
                              clickable={false}
                            />
                          ) : null}
                          {onToggleReplies && !!repliesCount && (
                            <TextButton
                              onClick={onToggleReplies}
                              variant="tertiary"
                              size="small"
                              iconPlacement="right"
                              icon={repliesOpen ? <SvgActionChevronT /> : <SvgActionChevronB />}
                            >
                              {repliesOpen ? 'Hide' : 'Show'} {repliesCount} {repliesCount === 1 ? 'reply' : 'replies'}
                            </TextButton>
                          )}
                          {onReplyClick && !isDeleted && !isProcessing && (commentHover || isTouchDevice) && (
                            <ReplyButton onClick={onReplyClick} variant="tertiary" size="small" _textOnly>
                              Reply
                            </ReplyButton>
                          )}
                        </RepliesWrapper>
                      </ReactionsWrapper>
                    }
                  />
                )}
              </CommentFooter>
            </CommentArticle>
          </CSSTransition>
        </SwitchTransition>
        <ContextMenu
          placement="bottom-end"
          disabled={loading || !shouldShowKebabButton}
          items={contexMenuItems}
          trigger={
            <KebabMenuIconButton
              icon={<SvgActionMore />}
              variant="tertiary"
              size="small"
              isActive={shouldShowKebabButton}
            />
          }
        />
      </CommentWrapper>
    </CommentRow>
  )
}
