import { pick } from 'lodash-es';
import React, { useCallback, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { twMerge } from 'tailwind-merge';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import HookMoreActionsMenu from '@/components/hooksPlayer/HookMoreActionsMenu';
import {
  ChevronDownIcon,
  ChevronUpIcon,
  CommentIcon,
  EyeIcon,
  HeartIcon,
  RemixIcon,
  ShareArrowIcon,
} from '@/icons';
import { getCountString } from '@/utils/utils';

import { HookActionHandler } from './constants';

export type HookActionsProps = {
  className?: string;
  buttonClassName?: string;
  buttonIconClassName?: string;
  buttonLabelClassName?: string;
  buttonVariant?: ButtonVariant;
  buttonSize?: ButtonSize;
  buttonShape?: ButtonShape;
  disabledPrevious?: boolean;
  disabledNext?: boolean;
  hookId?: string;
  clipId?: string;
  recommendationItemId?: string;
  creatorImageUrl?: string;
  creatorHandle?: string;
  creatorDisplayName?: string;
  currentUserHandle?: string;
  showFollowButton?: boolean;
  isFollowingCreator?: boolean;
  isRemixDisabled?: boolean;
  isLiked?: boolean;
  isNotInterested?: boolean;
  isPlaying?: boolean;
  isTestHook?: boolean;
  viewCount?: number;
  commentCount?: number;
  likeCount?: number;
  onPrevious?: HookActionHandler | null;
  onNext?: HookActionHandler | null;
  onFollow?: HookActionHandler<{ handle: string }> | null;
  onProfileClick?: HookActionHandler<{ handle: string }> | null;
  onRemix?: HookActionHandler<{ clipId: string }> | null;
  onLike?: HookActionHandler<{ isLike?: boolean }> | null;
  onNotInterested?: HookActionHandler<{ isNotInterested?: boolean }> | null;
  onComment?: HookActionHandler | null;
  onShare?: HookActionHandler | null;
  onHideCreator?: HookActionHandler<{ handle: string }> | null;
  onReport?: HookActionHandler | null;
  onDownload?: HookActionHandler | null;
  onFlag?: HookActionHandler | null;
  onToggleTest?: HookActionHandler<{ isTest?: boolean }> | null;
  onQualityLabelClick?: HookActionHandler<{ newLabel: string | null }> | null;
  onResetModeration?: HookActionHandler | null;
  onReprocess?: HookActionHandler | null;
  humanRating?: string | null;
};

export type Props = Omit<
  React.HTMLAttributes<HTMLDivElement>,
  keyof HookActionsProps
> &
  HookActionsProps;

const HookActions: React.FC<Props> = React.memo((props) => {
  const {
    className,
    buttonClassName,
    buttonIconClassName = 'w-6 h-6 m-0',
    buttonLabelClassName: explicitButtonLabelClassName,
    buttonVariant = ButtonVariant.ImageGlass,
    buttonSize = ButtonSize.Medium,
    buttonShape = ButtonShape.Pill,
    disabledPrevious,
    disabledNext,
    hookId,
    clipId,
    recommendationItemId,
    creatorImageUrl,
    creatorHandle,
    creatorDisplayName,
    currentUserHandle,
    showFollowButton,
    isFollowingCreator: isFollowing,
    isRemixDisabled = false,
    isLiked,
    isNotInterested,
    isPlaying,
    isTestHook,
    viewCount,
    commentCount,
    likeCount,
    onPrevious,
    onNext,
    onFollow,
    onProfileClick,
    onRemix,
    onLike,
    onNotInterested,
    onComment,
    onShare,
    onHideCreator,
    onReport,
    onDownload,
    onFlag,
    onToggleTest,
    onQualityLabelClick,
    onResetModeration,
    onReprocess,
    humanRating,
    ...restProps
  } = props;

  const { t } = useTranslation();

  const buttonLabelClassName = twMerge(
    'absolute top-full inset-x-0 mt-3 -mx-3',
    'font-mono font-semibold text-[10px] leading-3 text-center uppercase',
    'text-foreground-primary-glass',
    '[text-shadow:0_0_4px_rgba(0,0,0,0.5)]',
    explicitButtonLabelClassName
  );

  const actionPayloadRef = useRef({
    hookId: hookId || '',
    clipId: clipId || '',
    handle: creatorHandle || '',
    recommendationItemId,
    isFollowing,
    isLiked,
    isNotInterested,
    isTestHook,
  });
  useEffect(() => {
    actionPayloadRef.current.hookId = hookId || '';
    actionPayloadRef.current.clipId = clipId || '';
    actionPayloadRef.current.handle = creatorHandle || '';
    actionPayloadRef.current.recommendationItemId = recommendationItemId;
    actionPayloadRef.current.isFollowing = isFollowing;
    actionPayloadRef.current.isLiked = isLiked;
    actionPayloadRef.current.isNotInterested = isNotInterested;
    actionPayloadRef.current.isTestHook = isTestHook;
  }, [
    hookId,
    clipId,
    creatorHandle,
    recommendationItemId,
    isFollowing,
    isLiked,
    isNotInterested,
    isTestHook,
  ]);

  const handlePreviousClick = useCallback(
    (e: React.MouseEvent) => {
      onPrevious?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onPrevious]
  );
  const handleNextClick = useCallback(
    (e: React.MouseEvent) => {
      onNext?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onNext]
  );
  const handleRemixClick = useCallback(
    (e: React.MouseEvent) => {
      onRemix?.(
        pick(actionPayloadRef.current, [
          'hookId',
          'clipId',
          'recommendationItemId',
        ]),
        e
      );
    },
    [onRemix]
  );
  const handleLikeClick = useCallback(
    (e: React.MouseEvent) => {
      onLike?.(
        {
          ...pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
          isLike: !actionPayloadRef.current.isLiked,
        },
        e
      );
    },
    [onLike]
  );
  const handleNotInterestedClick = useCallback(
    (e: Event | React.MouseEvent) => {
      onNotInterested?.(
        {
          ...pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
          isNotInterested: !actionPayloadRef.current.isNotInterested,
        },
        e
      );
    },
    [onNotInterested]
  );
  const handleCommentClick = useCallback(
    (e: React.MouseEvent) => {
      onComment?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onComment]
  );
  const handleShareClick = useCallback(
    (e: React.MouseEvent) => {
      onShare?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onShare]
  );
  const handleHideCreatorClick = useCallback(
    (e: Event) => {
      onHideCreator?.(
        pick(actionPayloadRef.current, [
          'hookId',
          'handle',
          'recommendationItemId',
        ]),
        e
      );
    },
    [onHideCreator]
  );
  const handleReportClick = useCallback(
    (e: Event) => {
      onReport?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onReport]
  );
  const handleDownloadClick = useCallback(
    (e: Event) => {
      onDownload?.(pick(actionPayloadRef.current, ['hookId']), e);
    },
    [onDownload]
  );
  const handleFlagClick = useCallback(
    (e: Event) => {
      onFlag?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onFlag]
  );
  const handleToggleTestClick = useCallback(
    (e: Event) => {
      onToggleTest?.(
        {
          ...pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
          isTest: !actionPayloadRef.current.isTestHook,
        },
        e
      );
    },
    [onToggleTest]
  );
  const handleQualityLabelClick = useCallback(
    (newLabel: string | null, e: Event) => {
      onQualityLabelClick?.(
        {
          ...pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
          newLabel,
        },
        e
      );
    },
    [onQualityLabelClick]
  );
  const handleResetModerationClick = useCallback(
    (e: Event) => {
      onResetModeration?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onResetModeration]
  );
  const handleReprocessClick = useCallback(
    (e: Event) => {
      onReprocess?.(
        pick(actionPayloadRef.current, ['hookId', 'recommendationItemId']),
        e
      );
    },
    [onReprocess]
  );

  return (
    <div className={twMerge('flex flex-col gap-6', className)} {...restProps}>
      {onPrevious !== undefined ? (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={ChevronUpIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handlePreviousClick}
            disabled={disabledPrevious || !onPrevious}
          />
        </div>
      ) : null}
      {onNext !== undefined ? (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={ChevronDownIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handleNextClick}
            disabled={disabledNext || !onNext}
          />
        </div>
      ) : null}
      {viewCount == null ? null : (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={EyeIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            iconOnly
          >
            <span className={buttonLabelClassName}>
              {getCountString(viewCount)}
            </span>
          </Button>
        </div>
      )}
      {onRemix !== undefined ? (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={RemixIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handleRemixClick}
            disabled={isRemixDisabled}
            iconOnly
          >
            <span className={buttonLabelClassName}>
              {t('songActions.remix')}
            </span>
          </Button>
        </div>
      ) : null}
      {onLike !== undefined ? (
        <div>
          <Button
            className={
              isLiked
                ? twMerge('text-accent-pink', buttonClassName)
                : buttonClassName
            }
            iconClassName={buttonIconClassName}
            icon={HeartIcon}
            variant={isLiked ? ButtonVariant.Primary : buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handleLikeClick}
            disabled={!onLike}
            iconOnly
            aria-label={
              isLiked ? t('songActions.unlike') : t('songActions.like')
            }
          >
            {likeCount == null ? null : (
              <span className={buttonLabelClassName}>
                {getCountString(likeCount)}
              </span>
            )}
          </Button>
        </div>
      ) : null}
      {onComment !== undefined ? (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={CommentIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handleCommentClick}
            disabled={!onComment}
            iconOnly
          >
            {commentCount == null ? null : (
              <span className={buttonLabelClassName}>
                {getCountString(commentCount)}
              </span>
            )}
          </Button>
        </div>
      ) : null}
      {onShare !== undefined ? (
        <div>
          <Button
            className={buttonClassName}
            iconClassName={buttonIconClassName}
            icon={ShareArrowIcon}
            variant={buttonVariant}
            size={buttonSize}
            shape={buttonShape}
            onClick={handleShareClick}
            disabled={!onShare}
            iconOnly
          >
            <span className={buttonLabelClassName}>
              {t('songActions.share')}
            </span>
          </Button>
        </div>
      ) : null}
      {(onReport ||
        onFlag ||
        onToggleTest ||
        onQualityLabelClick ||
        onResetModeration ||
        onReprocess) &&
      hookId ? (
        <HookMoreActionsMenu
          hookId={hookId}
          isTestHook={isTestHook}
          humanRating={humanRating}
          buttonClassName={buttonClassName}
          buttonIconClassName={buttonIconClassName}
          buttonVariant={buttonVariant}
          buttonSize={buttonSize}
          buttonShape={buttonShape}
          onHideCreatorClick={
            onHideCreator ? handleHideCreatorClick : undefined
          }
          onReportClick={handleReportClick}
          onDownloadClick={onDownload ? handleDownloadClick : undefined}
          onNotInterestedClick={handleNotInterestedClick}
          onFlagClick={handleFlagClick}
          onToggleTestClick={handleToggleTestClick}
          onQualityLabelClick={handleQualityLabelClick}
          onResetModerationClick={handleResetModerationClick}
          onReprocessClick={handleReprocessClick}
        />
      ) : (
        <div className='-mb-2 h-0' />
      )}
    </div>
  );
});
HookActions.displayName = 'HookActions';

export default HookActions;
