import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import { useCallback, useEffect, useRef, useState } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { getMonthlyPriceForPlanAndCurrency } from '@/app/(root)/account/AuraSubscriptions/CurrencySelector';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { FeaturesAndPlansCarousel } from '@/components/modal/upsell-cards/FeaturesAndPlansCarousel';
import { useUsagePlanDescriptionsResponse } from '@/hooks/usePricing';
import { ThumbsDownIcon, ThumbsUpIcon } from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { FeatureKey, UsagePlanSchema } from '@/state/sessionStore';

import { MessageLikeStatus } from '../../stores';
import { useChatContext } from '../../useChat';
import { useChatMessageActions } from '../../useChatMessageActions';
import { StylesLyricsCard } from './StylesLyricsCard';

const OrpheusUpsell = observer(() => {
  const { menus, session } = useStores();
  const { data: descriptionsResponse } = useUsagePlanDescriptionsResponse();
  const usagePlanDescriptions = descriptionsResponse?.usage_plan_descriptions;

  const plans = [
    session.isSubLoaded
      ? session.sub.plans?.find(
          (plan: UsagePlanSchema) => plan.plan_key === 'pro'
        )
      : null,
    session.isSubLoaded
      ? session.sub.plans?.find(
          (plan: UsagePlanSchema) => plan.plan_key === 'premier'
        )
      : null,
  ].filter(Boolean);
  return (
    <FeaturesAndPlansCarousel
      features={menus.featureUpsellConfig || {}}
      currentUpsellFeature={FeatureKey.OUT_OF_CREDITS}
      currentSubscription={session.sub}
      usagePlanDescriptions={usagePlanDescriptions || {}}
      plans={plans}
      getMonthlyPriceForPlanAndCurrency={getMonthlyPriceForPlanAndCurrency}
      initialFeatureKey={FeatureKey.OUT_OF_CREDITS}
      carouselClassName='mx-0'
    />
  );
});

export const AssistantMessage = ({
  messageId,
  text,
  lyrics,
  styles,
  lyricsVersion,
  stylesVersion,
  shouldAnimate = true,
  isUpsell = false,
  onAllowChildScroll,
  likeStatus = null,
}: {
  messageId: string;
  text: string;
  lyrics?: string;
  styles?: string;
  lyricsVersion?: number;
  stylesVersion?: number;
  shouldAnimate?: boolean;
  isUpsell?: boolean;
  isLastMessage?: boolean;
  onAllowChildScroll: () => void;
  likeStatus?: MessageLikeStatus | null;
}) => {
  const wrapperRef = useRef<any>(null);
  const lastTokenRef = useRef<any>(null);
  const readyToRenderRef = useRef(true);
  const textLengthRenderedRef = useRef('');
  const fullTextRef = useRef<string>('');
  const { setMessageLikeStatus } = useChatMessageActions();
  const { session } = useStores();
  const { chatUUID } = useChatContext();

  // Track animation completion to fade in buttons after text animation
  const [isAnimationComplete, setIsAnimationComplete] =
    useState(!shouldAnimate);

  const renderText = useCallback(() => {
    if (!wrapperRef.current) return;
    if (!shouldAnimate) {
      wrapperRef.current.innerText = text;
      return;
    }
    const newText = fullTextRef.current.slice(
      textLengthRenderedRef.current.length
    );
    if (newText.length === 0) return;
    if (!readyToRenderRef.current) {
      return;
    }
    const newTokens = newText.split(' ');
    const delay = 50;
    readyToRenderRef.current = false;
    newTokens.forEach((token, index) => {
      const tokenEl = document.createElement('span');
      if (index === newTokens.length - 1) {
        tokenEl.innerText = token;
      } else {
        tokenEl.innerText = token + ' ';
      }
      tokenEl.style.opacity = '0';
      tokenEl.style.animation = 'fade-in ease-out forwards';
      tokenEl.style.animationDelay = `${index * delay}ms`;
      tokenEl.style.animationDuration = '300ms';
      if (index === newTokens.length - 1) {
        lastTokenRef.current = tokenEl;
      }
      wrapperRef.current.appendChild(tokenEl);
    });
    textLengthRenderedRef.current = fullTextRef.current;
    const handleAnimationEnd = () => {
      readyToRenderRef.current = true;
      if (fullTextRef.current.length > textLengthRenderedRef.current.length) {
        renderText();
      } else {
        // Mark animation as complete when all text is rendered
        setIsAnimationComplete(true);
      }
      lastTokenRef.current.removeEventListener(
        'animationend',
        handleAnimationEnd
      );
    };
    lastTokenRef.current.addEventListener('animationend', handleAnimationEnd);
  }, [text, shouldAnimate]);

  useEffect(() => {
    fullTextRef.current = text;
    renderText();
  }, [text]);

  const handleLike = useCallback(async () => {
    const newLikeStatus =
      likeStatus === MessageLikeStatus.LIKE ? null : MessageLikeStatus.LIKE;
    await setMessageLikeStatus(messageId, newLikeStatus);

    // Log the like action
    logWebUserEvent(
      {
        actionName: 'OrpheusMessageLiked',
        context: {
          sessionId: chatUUID,
          messageId: messageId,
          messageType: 'assistant',
          previousLikeStatus: likeStatus,
          newLikeStatus: newLikeStatus,
        },
      },
      session
    );
  }, [likeStatus, messageId, setMessageLikeStatus, session, chatUUID]);

  const handleDislike = useCallback(async () => {
    const newLikeStatus =
      likeStatus === MessageLikeStatus.DISLIKE
        ? null
        : MessageLikeStatus.DISLIKE;
    await setMessageLikeStatus(messageId, newLikeStatus);

    // Log the dislike action
    logWebUserEvent(
      {
        actionName: 'OrpheusMessageDisliked',
        context: {
          sessionId: chatUUID,
          messageId: messageId,
          messageType: 'assistant',
          previousLikeStatus: likeStatus,
          newLikeStatus: newLikeStatus,
        },
      },
      session
    );
  }, [likeStatus, messageId, setMessageLikeStatus, session, chatUUID]);

  return (
    <div className='flex flex-col gap-2'>
      <div
        className='max-w-[600px] text-foreground-primary'
        ref={wrapperRef}
      ></div>
      <div
        className={clsx('flex transition-opacity duration-300', {
          'opacity-0': !isAnimationComplete,
          'opacity-100': isAnimationComplete,
        })}
      >
        <Button
          className='group bg-transparent'
          aria-label={
            likeStatus === MessageLikeStatus.LIKE
              ? 'Remove like'
              : 'Like response'
          }
          aria-pressed={likeStatus === MessageLikeStatus.LIKE}
          iconClassName={clsx('h-5 w-5', {
            'fill-foreground-tertiary/50 group-hover:fill-foreground-tertiary':
              likeStatus !== MessageLikeStatus.LIKE,
            'fill-foreground-primary group-hover:fill-foreground-secondary':
              likeStatus === MessageLikeStatus.LIKE,
          })}
          icon={ThumbsUpIcon}
          onClick={handleLike}
          size={ButtonSize.Mini}
          shape={ButtonShape.Pill}
          variant={ButtonVariant.Glass}
        />
        <Button
          className='group bg-transparent'
          aria-label={
            likeStatus === MessageLikeStatus.DISLIKE
              ? 'Remove dislike'
              : 'Dislike response'
          }
          aria-pressed={likeStatus === MessageLikeStatus.DISLIKE}
          iconClassName={clsx('h-5 w-5', {
            'fill-foreground-tertiary/50 group-hover:fill-foreground-tertiary':
              likeStatus !== MessageLikeStatus.DISLIKE,
            'fill-foreground-primary group-hover:fill-foreground-secondary':
              likeStatus === MessageLikeStatus.DISLIKE,
          })}
          icon={ThumbsDownIcon}
          onClick={handleDislike}
          size={ButtonSize.Mini}
          shape={ButtonShape.Pill}
          variant={ButtonVariant.Glass}
        />
      </div>
      {lyrics || styles ? (
        <StylesLyricsCard
          lyrics={lyrics}
          styles={styles}
          lyricsVersion={lyricsVersion}
          stylesVersion={stylesVersion}
          onAllowChildScroll={onAllowChildScroll}
        />
      ) : null}

      {isUpsell ? (
        <div className='mt-8 max-w-[400px] overflow-hidden rounded-[20px]'>
          <OrpheusUpsell />
        </div>
      ) : null}
    </div>
  );
};
