'use client';

import { useStatsigClient } from '@statsig/react-bindings';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import { useModalContext } from '@/context/ModalContext';
import { EditIcon, PlusIcon } from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { Clip } from '@/state/clipStore';

import Link from '../link/Link';
import ProfileLink from '../link/ProfileLink';
import AuraTag from '../tag/AuraTag';

type ClipCaptionMention = {
  start: number;
  end: number;
  display_name?: string | null;
  handle: string;
};

interface ClipCaptionProps {
  caption?: string;
  clipId?: string;
  className?: string;
  maxLength?: number;
  isSongOwner?: boolean;
  clip?: Clip;
  displayButton?: boolean;
}

const ClipCaption = observer(
  ({
    caption,
    clipId,
    className,
    maxLength = 70,
    isSongOwner = false,
    clip,
    displayButton = false,
  }: ClipCaptionProps) => {
    const [isExpanded, setIsExpanded] = useState(false);
    const { clips, library } = useStores();
    const { openModal } = useModalContext();
    const statsigClient = useStatsigClient();
    const showCaptionsFeature = statsigClient.checkGate('web-captions');
    const pathname = usePathname();

    if (!showCaptionsFeature) {
      return null;
    }

    const storeClip = clipId ? clips.clipById[clipId] : null;

    const displayClip = storeClip || clip;
    const displayCaption = storeClip?.caption || caption;

    // Placeholder until we have an onboarding table
    const showNewTag = false;

    const handleAddCaption = () => {
      if (displayClip && isSongOwner) {
        library.setActiveClip(displayClip);
        openModal(ModalTypes.UPDATE_CLIP_METADATA, 'ClipCaption');

        // Use different event based on whether we're adding or editing
        if (displayCaption) {
          logWebUserEvent({
            actionName: 'EditCaptionButtonClicked',
            context: {
              clipId: clipId || '',
              page: pathname,
            },
          });
        } else {
          logWebUserEvent({
            actionName: 'AddCaptionButtonClicked',
            context: {
              clipId: clipId || '',
              page: pathname,
            },
          });
        }
      }
    };

    // Handle toggling caption expansion
    const handleToggleCaption = () => {
      const newExpandedState = !isExpanded;
      setIsExpanded(newExpandedState);

      logWebUserEvent({
        actionName: 'ExpandCaptionClicked',
        context: {
          clipId: clipId || '',
          caption: displayCaption || '',
          page: pathname,
          isExpanded: newExpandedState,
        },
      });
    };

    if (!displayCaption) {
      if (isSongOwner && clip?.preview_seconds === undefined) {
        if (displayButton) {
          return (
            <button
              onClick={handleAddCaption}
              className={twMerge(
                'flex w-full items-center justify-between rounded-[6px] bg-background-secondary px-[12px] py-[8px] text-left text-[12px] leading-[17px] font-normal text-foreground-secondary hover:text-foreground-primary',
                className
              )}
            >
              <span className='flex items-center gap-[3px]'>
                Add a Caption
                {showNewTag && (
                  <AuraTag
                    label='New'
                    gradient={
                      'linear-gradient(180deg, #FC7E85 0%, #C862A8 43%, #521B9C 100%)'
                    }
                  />
                )}
              </span>

              <PlusIcon className='h-3 w-3' />
            </button>
          );
        } else {
          return (
            <button
              onClick={handleAddCaption}
              className={twMerge(
                'w-fit text-[14px] text-foreground-secondary hover:text-foreground-primary',
                className
              )}
            >
              <span className='flex items-center gap-[3px]'>
                <span className='text-[#9F9C9C]'>Add a Caption</span>
                {showNewTag && (
                  <AuraTag
                    label='New'
                    gradient={
                      'linear-gradient(180deg, #FC7E85 0%, #C862A8 43%, #521B9C 100%)'
                    }
                  />
                )}
              </span>
            </button>
          );
        }
      }
      return null;
    }

    function renderHashtags(text: string) {
      if (!statsigClient.checkGate('hashtags')) {
        return <>{text}</>;
      }
      const regex = /(?<=^|\s)#(\w+)(?=\s|$)/g;

      // Split string into parts: text and hashtags
      const parts = [];
      let lastIndex = 0;

      for (const match of text.matchAll(regex)) {
        const { index } = match;
        const tag = match[1];

        if (index !== undefined) {
          // push text before link
          parts.push(text.slice(lastIndex, index));

          // push tag as a link
          parts.push(
            <Link
              key={`hashtag-${index}`}
              href={`/hashtag/${tag}`}
              className='text-foreground-secondary hover:underline'
              onClick={() => {
                logWebUserEvent({
                  actionName: 'HashtagClicked',
                  context: {
                    clipId: clipId || '',
                    hashtag: tag,
                  },
                });
              }}
            >
              #{tag}
            </Link>
          );

          lastIndex = index + match[0].length;
        }
      }

      // push any remaining text after the last hashtag
      if (lastIndex < text.length) {
        parts.push(text.slice(lastIndex));
      }

      return <>{parts}</>;
    }

    function renderCaptionWithMentionsAndHashtags(
      caption: string,
      mentions: ClipCaptionMention[],
      shouldTruncate: boolean,
      maxLength: number,
      isExpanded: boolean
    ) {
      if ((!mentions || mentions.length === 0) && !caption.includes('#')) {
        const displayText =
          shouldTruncate && !isExpanded ? caption.slice(0, maxLength) : caption;
        return <span>{displayText}</span>;
      }

      // sort mentions by start position
      const sortedMentions = [...mentions].sort((a, b) => a.start - b.start);

      const elements: React.ReactNode[] = [];
      let currentPosition = 0;
      let currentLength = 0;

      for (let i = 0; i < sortedMentions.length; i++) {
        const mention = sortedMentions[i];

        // add text before the mention
        const textBefore = caption.slice(currentPosition, mention.start);
        if (textBefore) {
          // check if we need to truncate this text segment
          if (
            shouldTruncate &&
            !isExpanded &&
            currentLength + textBefore.length > maxLength
          ) {
            const remainingLength = maxLength - currentLength;
            if (remainingLength > 0) {
              elements.push(
                <span key={`text-${i}`}>
                  {renderHashtags(textBefore.slice(0, remainingLength))}
                </span>
              );
            }
            return <>{elements}</>;
          }

          elements.push(
            <span key={`text-${i}`}>{renderHashtags(textBefore)}</span>
          );
          currentLength += textBefore.length;
        }

        // handle mention truncation if needed
        let mentionDisplayText = mention.display_name || `@${mention.handle}`;
        let mentionDisplayLength = mentionDisplayText.length;

        if (
          shouldTruncate &&
          !isExpanded &&
          currentLength + mentionDisplayLength > maxLength
        ) {
          const remainingLength = maxLength - currentLength;
          if (remainingLength <= 0) {
            return <>{elements}</>;
          }

          // truncate the mention display name to fit
          mentionDisplayText = mentionDisplayText.slice(0, remainingLength);
          mentionDisplayLength = remainingLength;
        }

        elements.push(
          <ProfileLink
            key={`mention-${i}`}
            handle={mention.handle}
            className='font-bold text-foreground-primary hover:text-foreground-secondary hover:underline'
          >
            {mentionDisplayText}
          </ProfileLink>
        );

        currentLength += mentionDisplayLength;

        // if we truncated the mention, we've reached our limit
        if (
          shouldTruncate &&
          !isExpanded &&
          mentionDisplayText !== (mention.display_name || `@${mention.handle}`)
        ) {
          return <>{elements}</>;
        }
        currentPosition = mention.end;
      }

      // handle remaining text after all mentions
      const remainingText = caption.slice(currentPosition);
      if (remainingText) {
        // check if we need to truncate this remaining text
        if (
          shouldTruncate &&
          !isExpanded &&
          currentLength + remainingText.length > maxLength
        ) {
          const remainingLength = maxLength - currentLength;
          if (remainingLength > 0) {
            elements.push(
              <span key='text-end'>
                {renderHashtags(remainingText.slice(0, remainingLength))}
              </span>
            );
          }
        } else {
          elements.push(
            <span key='text-end'>{renderHashtags(remainingText)}</span>
          );
        }
      }

      return <>{elements}</>;
    }

    // Check if we should truncate based on original caption length
    const shouldTruncate = displayCaption.length > maxLength;

    // parse the caption with mentions and handle truncation
    const renderedCaption = renderCaptionWithMentionsAndHashtags(
      displayCaption,
      displayClip?.caption_mentions?.user_mentions || [],
      shouldTruncate,
      maxLength,
      isExpanded
    );

    return (
      <div
        className={twMerge(
          `text-[14px] leading-[20px] font-normal text-foreground-primary ${displayButton ? 'px-[2px]' : ''} whitespace-normal`,
          className
        )}
      >
        {renderedCaption}
        {shouldTruncate && (
          <button
            onClick={handleToggleCaption}
            className='font-semibold text-foreground-secondary hover:text-foreground-primary'
          >
            {isExpanded ? 'Less' : '... More'}
          </button>
        )}
        {isSongOwner &&
          displayCaption &&
          clip?.preview_seconds === undefined && (
            <button
              onClick={handleAddCaption}
              className='ml-1 inline-flex scale-90 items-center align-middle text-foreground-secondary opacity-76 hover:text-foreground-primary'
              aria-label='Edit caption'
            >
              <EditIcon className='h-3.5 w-3.5' />
            </button>
          )}
      </div>
    );
  }
);

export default ClipCaption;
