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

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import Link from '@/components/link/Link';
import ArtistTag from '@/components/tag/ArtistTag';
import useFollowUser from '@/hooks/useFollowUser';
import useParentClip from '@/hooks/useParentClip';
import { RemixIcon } from '@/icons';
import { generateLinkUrl } from '@/utils/embeds';

import { HookActionHandler } from './constants';

export type HookMetadataProps = {
  className?: string;
  authorClassName?: string;
  captionClassName?: string;
  hookId?: string;
  title?: string;
  displayName?: string;
  handle?: string;
  avatarImageUrl?: string;
  caption?: string;
  clipId?: string;
  recommendationItemId?: string;
  currentUserHandle?: string;
  isRemix?: boolean;
  isPlaying?: boolean;
  isFollowingCreator?: boolean;
  onCreatorClick?: HookActionHandler<{ handle: string }> | null;
  onFollow?: HookActionHandler<{ handle: string }> | null;
};

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

const HookMetadata: React.FC<Props> = React.memo((props) => {
  const {
    children,
    className,
    authorClassName,
    captionClassName,
    hookId,
    title,
    displayName,
    handle,
    avatarImageUrl,
    caption,
    clipId,
    recommendationItemId,
    currentUserHandle,
    isRemix,
    isPlaying,
    isFollowingCreator,
    onCreatorClick,
    onFollow,
    ...restProps
  } = props;

  const { t } = useTranslation();

  const { parentClip: remixClip } = useParentClip({
    clipId: isRemix ? clipId || '' : '',
  });

  const { isFollowing, setIsFollowing } = useFollowUser(
    handle || '',
    isFollowingCreator || false,
    {
      recommendationItemId,
      hookId,
    }
  );

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

  const shouldShowFollowButton =
    !!handle && !!currentUserHandle && currentUserHandle !== handle;

  const handleCreatorClick = useCallback(
    (e: React.MouseEvent) => {
      onCreatorClick?.(
        pick(actionPayloadRef.current, [
          'hookId',
          'handle',
          'recommendationItemId',
        ]),
        e
      );
    },
    [onCreatorClick]
  );

  const handleFollowClick = useCallback(
    (e: React.MouseEvent) => {
      onFollow?.(
        pick(actionPayloadRef.current, [
          'hookId',
          'handle',
          'recommendationItemId',
        ]),
        e
      );
      setIsFollowing(!isFollowing);
    },
    [onFollow, isFollowing, setIsFollowing]
  );

  const [showFullCaption, setShowFullCaption] = useState(false);
  const [captionRef, setCaptionRef] = useState<HTMLDivElement | null>(null);
  useEffect(() => {
    if (captionRef) {
      let allowHover = true;
      let allowClick = true;
      let hoverTimeout: NodeJS.Timeout;
      let clickTimeout: NodeJS.Timeout;
      const handleMouseEnter = () => {
        clearTimeout(hoverTimeout);
        allowClick = false;
        hoverTimeout = setTimeout(() => {
          setShowFullCaption(true);
          clickTimeout = setTimeout(() => {
            allowClick = true;
          }, 300);
        }, 700);
      };
      const handleMouseLeave = () => {
        clearTimeout(hoverTimeout);
        clearTimeout(clickTimeout);
        allowClick = true;
        if (allowHover) {
          setShowFullCaption(false);
        }
      };
      const handleClick = () => {
        if (!allowClick) return;
        clearTimeout(hoverTimeout);
        setShowFullCaption((prevShowFullCaption) => {
          allowHover = prevShowFullCaption;
          if (!(document.getSelection()?.isCollapsed ?? true)) {
            return prevShowFullCaption;
          }
          return !prevShowFullCaption;
        });
      };
      captionRef.addEventListener('mouseenter', handleMouseEnter);
      captionRef.addEventListener('mouseleave', handleMouseLeave);
      captionRef.addEventListener('click', handleClick);
      return () => {
        captionRef.removeEventListener('mouseenter', handleMouseEnter);
        captionRef.removeEventListener('mouseleave', handleMouseLeave);
        captionRef.removeEventListener('click', handleClick);
        clearTimeout(hoverTimeout);
        clearTimeout(clickTimeout);
      };
    }
  }, [captionRef]);

  return (
    <div
      className={twMerge('relative flex flex-col gap-2', className)}
      {...restProps}
    >
      {children}
      {handle ? (
        <div className='flex flex-row items-center gap-2'>
          <ArtistTag
            className={authorClassName}
            displayName={displayName}
            handle={handle}
            imageUrl={avatarImageUrl || ''}
            onClick={onCreatorClick ? handleCreatorClick : undefined}
          />
          {shouldShowFollowButton && (
            <Button
              className='px-2 py-1'
              variant={ButtonVariant.Secondary}
              size={ButtonSize.Micro}
              shape={ButtonShape.Pill}
              onClick={handleFollowClick}
              active={isFollowing}
            >
              {isFollowing ? t('profile.following') : t('profile.follow')}
            </Button>
          )}
        </div>
      ) : null}
      {caption ? (
        <div
          className={twMerge(
            clsx(
              'max-w-160 pr-12 text-foreground-primary-on-dark',
              'line-clamp-[var(--overflow-line-clamp,none)]',
              'max-h-[calc(var(--overflow-line-clamp,none)*1lh)]',
              'transition-[max-height] duration-0',
              '[--overflow-line-clamp:2]',
              {
                'duration-300 [--overflow-line-clamp:10]': showFullCaption,
              }
            ),
            captionClassName
          )}
          ref={setCaptionRef}
        >
          {caption.split('\n\n').map((paragraph, i) => (
            <p key={i}>
              {paragraph.split('\n').map((line, j) =>
                j ? (
                  <React.Fragment key={j}>
                    <br />
                    {line}
                  </React.Fragment>
                ) : (
                  line
                )
              )}
            </p>
          ))}
        </div>
      ) : null}
      {remixClip != null && (remixClip.id || remixClip.user_handle) ? (
        <Button
          className='self-start px-3 py-0'
          variant={ButtonVariant.LightGlass}
          shape={ButtonShape.Pill}
          size={ButtonSize.Micro}
          icon={RemixIcon}
          iconClassName='size-3'
          // href={generateLinkUrl(remixClip.id || '', 'song')}
        >
          <Trans
            t={t}
            i18nKey='song.remixOf'
            values={{
              other: remixClip.user_display_name || remixClip.user_handle || '',
            }}
            components={{
              remixType: (
                <Link
                  className='hover:underline'
                  href={
                    remixClip.id
                      ? generateLinkUrl(remixClip.id, 'song')
                      : remixClip.user_handle
                        ? generateLinkUrl(remixClip.user_handle, 'profile')
                        : '#'
                  }
                />
              ),
              remixParent: (
                <ArtistTag
                  className='gap-0 text-[size:inherit]'
                  avatarWrapClassName='h-6'
                  displayName={remixClip.user_display_name}
                  handle={remixClip.user_handle || ''}
                  imageUrl={remixClip.user_avatar_image_url || ''}
                />
              ),
            }}
          />
        </Button>
      ) : null}
    </div>
  );
});
HookMetadata.displayName = 'HookMetadata';

export default HookMetadata;
