'use client';

import { FormControl } from '@chakra-ui/react';
import { useGateValue, useStatsigClient } from '@statsig/react-bindings';
import clsx from 'clsx';
import { throttle } from 'lodash-es';
import { observer } from 'mobx-react-lite';
import {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { UploadState } from '@/app/(root)/create/sandbox/VideoUploadState';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import CaptionInput from '@/components/caption/CaptionInput';
import HashtagSuggestions from '@/components/caption/HashtagSuggestions';
import MentionSuggestions from '@/components/comment/MentionSuggestions';
import { extractCurrentWord } from '@/components/comment/utils';
import ImageWithFallback from '@/components/image/ImageWithFallback';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import {
  DISPLAY_HEIGHT,
  DISPLAY_WIDTH,
} from '@/components/modal/editClipMetadata/constants';
import ModalNavigationLabel from '@/components/modal/publishSong/ModalNavigationLabel';
import TextareaV2 from '@/components/textarea/TextareaV2';
import { toast } from '@/components/toast/Toast';
import { Tooltip } from '@/components/tooltip/Tooltip';
import ContestClipContext from '@/hooks/useContestClip';
import useParentClip from '@/hooks/useParentClip';
import SongModalContext from '@/hooks/useSongModal';
import {
  GearIcon,
  LyricsIcon,
  PhotoGalleryIcon,
  SparklesIcon,
  SuccessIcon,
  TrashIcon,
} from '@/icons';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { Clip } from '@/state/clipStore';
import {
  DEFAULT_AURA_URL,
  LARGE_IMAGE,
  MAX_TITLE_CHARS,
  MENTION_CLEANUP_REGEX,
} from '@/utils/constants';

import LabelWithSwitch from './LabelWithSwitch';

export type PublishModalEditClipSectionProps = {
  clipId: string;
  editedTitle: string;
  setEditedTitle: (title: string) => void;
  currentActiveClip?: Clip;
  currentImage: any;
  setCurrentImage: (image: any) => void;
  continuedClips: Clip[];
  addedImages: (string | null)[];
  audioUploadClipMetadata?: any;
  currentCaption?: string;
  setCurrentCaption: React.Dispatch<React.SetStateAction<string>>;
  mentionQuery: string | null;
  setMentionQuery: React.Dispatch<React.SetStateAction<string | null>>;
  hashtagQuery: string | null;
  setHashtagQuery: React.Dispatch<React.SetStateAction<string | null>>;
  selectedVideo?: File | null;
  setSelectedVideo: (video: File | null) => void;
  setIsAddingMedia?: (isAdding: boolean) => void;
  uploadState?: UploadState;
  displayTags?: string;
  setDisplayTags: (tags: string) => void;
  submitToContest: boolean;
  setSubmitToContest: (submitToContest: boolean) => void;
  hasSubmitToContestChanged: boolean;
  setIsGeneratingCover?: (isGenerating: boolean) => void;
  stateRef: React.RefObject<{
    currentCaption: string;
    mentionQuery: string | null;
    mentionSuggestion: {
      handle: string | null;
      displayName: string | null;
      isExact: boolean;
    };
    mentionsUsedMap: Map<string, string>;
    hashtagQuery: string | null;
    hashtagSuggestion: string | null;
  }>;
  setInitialImageURLForVideoGen: (imageUrl: string | null) => void;
};
export const PublishModalEditClipSection = observer(
  ({
    clipId,
    editedTitle,
    setEditedTitle,
    currentActiveClip,
    currentImage,
    setCurrentImage,
    audioUploadClipMetadata,
    currentCaption,
    setCurrentCaption,
    mentionQuery,
    setMentionQuery,
    hashtagQuery,
    setHashtagQuery,
    selectedVideo,
    setSelectedVideo,
    setIsAddingMedia,
    uploadState,
    displayTags,
    setDisplayTags,
    submitToContest,
    setSubmitToContest,
    setIsGeneratingCover,
    hasSubmitToContestChanged,
    setInitialImageURLForVideoGen,
    stateRef,
  }: PublishModalEditClipSectionProps) => {
    const statsigClient = useStatsigClient();
    const enableHashtags = useGateValue('hashtags');
    const showCaptionsFeature = statsigClient.checkGate('web-captions');
    const enableGenerateCovers = useGateValue('gen-video-covers');
    const { navigateTo, modalType } = useContext(SongModalContext);
    const { isContestEligible } = useContext(ContestClipContext);

    const hasVideo =
      !!selectedVideo ||
      (selectedVideo !== null && !!currentActiveClip?.video_cover_url);

    const showDisplayTags =
      currentActiveClip?.major_model_version === 'v4.5' ||
      currentActiveClip?.major_model_version === 'v4.5+' ||
      currentActiveClip?.major_model_version === 'v4.5-all' ||
      currentActiveClip?.major_model_version === 'v5' ||
      currentActiveClip?.metadata?.type === 'studio_export' ||
      currentActiveClip?.metadata?.type === 'upload' ||
      displayTags;

    const { session, clips } = useStores();

    const { parentClip, isLoadingParentClip } = useParentClip({ clipId });
    const isOwnRemix = parentClip?.user_handle === session.user.handle;
    const [showRemixOrigin, setShowRemixOrigin] = useState<boolean | null>(
      null
    );

    useEffect(() => {
      if (!isLoadingParentClip) {
        setShowRemixOrigin(
          Boolean(currentActiveClip?.metadata?.show_remix || !isOwnRemix)
        );
      }
    }, [
      currentActiveClip?.metadata?.show_remix,
      isOwnRemix,
      isLoadingParentClip,
    ]);

    const showContestToggle = useMemo(
      () =>
        isContestEligible({ clip: currentActiveClip }) &&
        (modalType === ModalTypes.PUBLISH_SONG || currentActiveClip?.is_public),
      [currentActiveClip, isContestEligible, modalType]
    );

    const disableContestToggle = useMemo(
      () =>
        modalType === ModalTypes.UPDATE_CLIP_METADATA &&
        submitToContest &&
        !hasSubmitToContestChanged,
      [modalType, submitToContest, hasSubmitToContestChanged]
    );

    const handleSubmitToContest = useCallback(
      ({ isEntering }: { isEntering: boolean }) => {
        setSubmitToContest(isEntering);
      },
      [setSubmitToContest]
    );

    const handleRemixToggle = async (checked: boolean) => {
      setShowRemixOrigin(checked);

      if (clipId && currentActiveClip) {
        try {
          await clips.toggleShowRemixes(clipId, checked);

          // logWebUserEvent({
          //   actionName: 'RemixOriginToggled',
          //   principalObjectType: 'song',
          //   principalObjectValue: clipId,
          //   context: {
          //     clipId,
          //     showRemixOrigin: checked,
          //   },
          // });
        } catch (error) {
          setShowRemixOrigin(!checked);

          toast({
            title: 'Error',
            description: 'Failed to update remix origin visibility',
            status: 'error',
            duration: 5000,
            isClosable: true,
          });
        }
      }
    };

    useEffect(() => {
      stateRef.current.currentCaption = currentCaption || '';
    }, [currentCaption]);
    useEffect(() => {
      stateRef.current.mentionQuery = mentionQuery;
    }, [mentionQuery]);
    useEffect(() => {
      stateRef.current.hashtagQuery = hashtagQuery;
    }, [hashtagQuery]);

    const mentionCursorRef = useRef<[word: string, start: number, end: number]>(
      ['', 0, 0]
    );
    const hashtagCursorRef = useRef<[word: string, start: number, end: number]>(
      ['', 0, 0]
    );
    const textareaRef = useRef<HTMLTextAreaElement>(null);
    const parseMention = useMemo(
      () =>
        throttle((value: string) => {
          stateRef.current.mentionSuggestion = {
            handle: null,
            displayName: null,
            isExact: false,
          };
          if (
            textareaRef.current &&
            textareaRef.current.selectionStart ===
              textareaRef.current.selectionEnd
          ) {
            mentionCursorRef.current = extractCurrentWord(
              value,
              textareaRef.current.selectionStart
            );
            const [currentWord] = mentionCursorRef.current;
            if (currentWord.startsWith('@')) {
              setMentionQuery(
                currentWord.replace(MENTION_CLEANUP_REGEX, '').slice(1)
              );
            } else {
              setMentionQuery(null);
            }
          }
        }, 250),
      []
    );

    const parseHashtag = useMemo(
      () =>
        throttle((value: string) => {
          stateRef.current.hashtagSuggestion = null;
          if (
            textareaRef.current &&
            textareaRef.current.selectionStart ===
              textareaRef.current.selectionEnd
          ) {
            hashtagCursorRef.current = extractCurrentWord(
              value,
              textareaRef.current.selectionStart
            );
            const [currentWord] = hashtagCursorRef.current;
            if (currentWord.startsWith('#')) {
              const hashtagTerm = currentWord
                .replace(/[^#a-zA-Z0-9_]/g, '')
                .slice(1);
              setHashtagQuery(hashtagTerm);
            } else {
              setHashtagQuery(null);
            }
          }
        }, 250),
      []
    );

    // @TODO: This would probably be less janky if it was done on keyup
    useEffect(() => {
      parseMention(currentCaption || '');
    }, [currentCaption, parseMention]);
    useEffect(() => {
      parseHashtag(currentCaption || '');
    }, [currentCaption, parseHashtag]);

    const handleKeyDown = useCallback(
      (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
        switch (true) {
          case e.key === 'Escape':
            setMentionQuery(null);
            setHashtagQuery(null);
            break;
          case e.key === 'Tab' && !!stateRef.current.mentionSuggestion.handle:
            const { handle, displayName } = stateRef.current.mentionSuggestion;

            // Keep track of the mention we used so we can replace it later on
            stateRef.current.mentionsUsedMap.set(
              handle,
              displayName || `@${handle}`
            );

            const [currentWord, start, end] = mentionCursorRef.current;
            const replacementWord = currentWord.startsWith('@')
              ? `@${handle}`
              : handle;
            setCurrentCaption((prevInputValue) =>
              [
                prevInputValue.slice(0, start),
                replacementWord,
                ' ', // Add a space after the suggestion
                prevInputValue.slice(end),
              ].join('')
            );
            const cursorPosition = start + replacementWord.length + 1;
            // Wait a frame
            setTimeout(() => {
              if (textareaRef.current) {
                textareaRef.current.focus();
                textareaRef.current.setSelectionRange(
                  cursorPosition,
                  cursorPosition,
                  'none'
                );
              }
              // Hide the suggestions
              setMentionQuery(null);
            }, 0);
            e.preventDefault();
            break;
          case e.key === 'Tab' && !!stateRef.current.hashtagSuggestion:
            const hashtag = stateRef.current.hashtagSuggestion;

            const [currentHashtagWord, hashtagStart, hashtagEnd] =
              hashtagCursorRef.current;
            const hashtagReplacementWord = currentHashtagWord.startsWith('#')
              ? `#${hashtag}`
              : hashtag;
            setCurrentCaption((prevInputValue) =>
              [
                prevInputValue.slice(0, hashtagStart),
                hashtagReplacementWord,
                ' ', // Add a space after the suggestion
                prevInputValue.slice(hashtagEnd),
              ].join('')
            );
            const hashtagCursorPosition =
              hashtagStart + hashtagReplacementWord.length + 1;
            // Wait a frame
            setTimeout(() => {
              if (textareaRef.current) {
                textareaRef.current.focus();
                textareaRef.current.setSelectionRange(
                  hashtagCursorPosition,
                  hashtagCursorPosition,
                  'none'
                );
              }
              // Hide the suggestions
              setHashtagQuery(null);
            }, 0);
            e.preventDefault();
            break;
          default:
            break;
        }
      },
      []
    );

    const handleSuggestion = useCallback(
      (value: string, displayValue: string) => {
        // Determine if this is a mention or hashtag based on current queries
        if (mentionQuery !== null) {
          // This is a mention suggestion
          stateRef.current.mentionSuggestion = {
            handle: value,
            displayName: displayValue,
            isExact: stateRef.current.mentionQuery === value,
          };
        } else if (hashtagQuery !== null) {
          // This is a hashtag suggestion
          stateRef.current.hashtagSuggestion = value;
        }
      },
      [mentionQuery, hashtagQuery]
    );

    const handleMentionSelect = useCallback(
      (handle: string, displayName: string) => {
        // Keep track of the mention we used so we can replace it later on
        stateRef.current.mentionsUsedMap.set(handle, displayName);

        const [currentWord, start, end] = mentionCursorRef.current;
        const replacementWord = currentWord.startsWith('@')
          ? `@${handle}`
          : handle;
        setCurrentCaption((prevInputValue) =>
          [
            prevInputValue.slice(0, start),
            replacementWord,
            prevInputValue.slice(end),
          ].join('')
        );
        const cursorPosition = start + replacementWord.length;
        // Wait a frame
        setTimeout(() => {
          if (textareaRef.current) {
            textareaRef.current.focus();
            textareaRef.current.setSelectionRange(
              cursorPosition,
              cursorPosition,
              'none'
            );
          }
          // Hide the suggestions
          setMentionQuery(null);
        }, 0);
      },
      []
    );

    const handleHashtagSelect = useCallback((hashtag: string) => {
      const [currentWord, start, end] = hashtagCursorRef.current;
      const replacementWord = currentWord.startsWith('#')
        ? `#${hashtag}`
        : hashtag;
      setCurrentCaption((prevInputValue) =>
        [
          prevInputValue.slice(0, start),
          replacementWord,
          prevInputValue.slice(end),
        ].join('')
      );
      const cursorPosition = start + replacementWord.length;
      setTimeout(() => {
        if (textareaRef.current) {
          textareaRef.current.focus();
          textareaRef.current.setSelectionRange(
            cursorPosition,
            cursorPosition,
            'none'
          );
        }
        // Hide the suggestions
        setHashtagQuery(null);
      }, 0);
    }, []);

    return (
      <div className={'align-start flex flex-col gap-4 px-6 md:flex-row'}>
        {(currentActiveClip?.status === 'complete' ||
          audioUploadClipMetadata) && (
          <div className='flex min-w-40 flex-col items-center gap-2'>
            <div
              className='relative aspect-9/16 overflow-hidden rounded-lg'
              style={{ height: DISPLAY_HEIGHT }}
            >
              {hasVideo ? (
                <div className='relative'>
                  <video
                    src={
                      selectedVideo
                        ? URL.createObjectURL(selectedVideo)
                        : currentActiveClip?.video_cover_url || ''
                    }
                    controls
                    style={{
                      width: DISPLAY_WIDTH,
                      height: DISPLAY_HEIGHT,
                      objectFit: 'cover',
                    }}
                    controlsList='nodownload nofullscreen noremoteplayback'
                  />
                  {uploadState?.isUploading && (
                    <div className='absolute inset-0 flex items-center justify-center bg-black/70 text-white'>
                      <p>Uploading...</p>
                    </div>
                  )}
                  {uploadState?.isProcessing && (
                    <div className='absolute inset-0 flex items-center justify-center bg-black/70 text-white'>
                      <p>Processing...</p>
                    </div>
                  )}
                </div>
              ) : (
                <ImageWithFallback
                  className='h-full w-full object-cover'
                  alt=''
                  src={currentImage || undefined}
                  imageSize={LARGE_IMAGE}
                  fallbackSrc={DEFAULT_AURA_URL}
                />
              )}
              {currentImage &&
              currentImage !== DEFAULT_AURA_URL &&
              !hasVideo &&
              enableGenerateCovers ? (
                <Button
                  className='absolute bottom-2 left-1/2 -translate-x-1/2 text-white'
                  variant={ButtonVariant.Smoke}
                  size={ButtonSize.Small}
                  shape={ButtonShape.Pill}
                  onClick={() => {
                    setIsGeneratingCover?.(true);
                    setInitialImageURLForVideoGen(currentImage || null);
                    logWebUserEvent({
                      actionName: 'SongEditCoverArtClicked',
                      principalObjectType: 'song',
                      principalObjectValue: clipId,
                      context: { clipId, mediaType: 'video' },
                    });
                  }}
                  icon={SparklesIcon}
                  aria-label='Animate Cover'
                >
                  Animate
                </Button>
              ) : null}
              {(currentImage && currentImage !== DEFAULT_AURA_URL) ||
              hasVideo ? (
                <Button
                  className='absolute top-2 right-2'
                  variant={ButtonVariant.Fog}
                  size={ButtonSize.Small}
                  shape={ButtonShape.Pill}
                  onClick={() => {
                    setCurrentImage(null);
                    setSelectedVideo(null);
                  }}
                  icon={TrashIcon}
                  aria-label='Remove Cover Art'
                />
              ) : null}
            </div>
            <div className='flex w-full flex-col gap-2'>
              {enableGenerateCovers && (
                <Button
                  onClick={() => {
                    setIsGeneratingCover?.(true);
                    logWebUserEvent({
                      actionName: 'SongEditCoverArtGenerateClicked',
                      principalObjectType: 'song',
                      principalObjectValue: clipId,
                      context: { clipId, mediaType: 'video' },
                    });
                  }}
                  icon={SparklesIcon}
                  className='w-full'
                >
                  Generate Cover Art
                </Button>
              )}
              <Button
                onClick={() => {
                  // Use unified media upload if available, otherwise fall back to video only
                  if (setIsAddingMedia) {
                    setIsAddingMedia(true);
                  }
                  logWebUserEvent({
                    actionName: 'SongEditCoverArtClicked',
                    principalObjectType: 'song',
                    principalObjectValue: clipId,
                    context: {
                      clipId,
                      mediaType: 'video', // Keep as 'video' for backward compatibility
                    },
                  });
                }}
                icon={PhotoGalleryIcon}
                className='w-full'
              >
                {'Add Photo/Video'}
              </Button>
            </div>
          </div>
        )}

        <div
          className={clsx('flex flex-1 flex-col', {
            'gap-3': showDisplayTags,
            'gap-4': !showDisplayTags,
          })}
        >
          <FormControl>
            <Tooltip
              label='Title'
              isTooltipEnabled={!!editedTitle}
              placement='top-start'
              openDelay={100}
              closeOnClick
            >
              <TextareaV2
                maxRows={1}
                maxLength={MAX_TITLE_CHARS}
                value={editedTitle || ''}
                onChange={(e) => {
                  const filteredValue = e.target.value.replace(/\n/g, '');
                  setEditedTitle(filteredValue);
                }}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    e.preventDefault();
                  }
                }}
                placeholder={'Add a title...'}
              />
            </Tooltip>
          </FormControl>

          {showCaptionsFeature && (
            <FormControl>
              <Tooltip
                label='Caption'
                isTooltipEnabled={!!currentCaption}
                placement='top-start'
                openDelay={100}
                closeOnClick
              >
                <div className='relative'>
                  <CaptionInput
                    parentClip={!!parentClip}
                    showDisplayTags={!!showDisplayTags}
                    showContestToggle={!!showContestToggle}
                    currentCaption={currentCaption || ''}
                    setCurrentCaption={setCurrentCaption}
                    onKeyDown={handleKeyDown}
                    ref={textareaRef}
                  />
                  <MentionSuggestions
                    className='absolute inset-x-0 top-[calc(100%+0.25rem)] z-1 bg-background-tertiary'
                    query={mentionQuery}
                    onSelect={handleMentionSelect}
                    onSuggestion={handleSuggestion}
                  />
                  {enableHashtags ? (
                    <HashtagSuggestions
                      className='absolute inset-x-0 top-[calc(100%+0.25rem)] z-1 bg-background-tertiary'
                      query={hashtagQuery}
                      onSelect={handleHashtagSelect}
                      onSuggestion={handleSuggestion}
                    />
                  ) : null}
                </div>
              </Tooltip>
            </FormControl>
          )}
          {showDisplayTags && (
            <FormControl>
              <Tooltip
                label='Displayed Style Summary'
                isTooltipEnabled={!!displayTags}
                placement='top-start'
                openDelay={100}
                closeOnClick
              >
                <TextareaV2
                  maxRows={1}
                  maxLength={100}
                  value={displayTags?.slice(0, 100) || ''}
                  resize={true}
                  textAreaClassName='pb-2.5'
                  onChange={(e) => {
                    const filteredValue = e.target.value.replace(/\n/g, '');
                    setDisplayTags(filteredValue);
                  }}
                  placeholder={'Add a style summary...'}
                />
              </Tooltip>
            </FormControl>
          )}
          {(currentActiveClip?.status === 'complete' ||
            audioUploadClipMetadata) && (
            <div className='flex flex-col'>
              {showContestToggle && (
                <div className='flex flex-col'>
                  <LabelWithSwitch
                    label={'Submit Remix to Contest'}
                    checked={submitToContest}
                    onChange={(isEntering) =>
                      handleSubmitToContest({
                        isEntering,
                      })
                    }
                    className={clsx(
                      'rounded-t-md rounded-b-none border-b-0 text-sm'
                    )}
                    icon={SuccessIcon}
                    disabled={disableContestToggle}
                    tooltipText={
                      disableContestToggle
                        ? 'Unpublish your song to withdraw from the contest'
                        : undefined
                    }
                  />
                </div>
              )}
              {!!parentClip && (
                <LabelWithSwitch
                  label={isOwnRemix ? 'Show Remix Origin' : 'Remix Origin'}
                  checked={showRemixOrigin ?? false}
                  onChange={handleRemixToggle}
                  image={parentClip.image_url || undefined}
                  className={clsx('rounded-t-md rounded-b-none border-b-0', {
                    'rounded-t-none': showContestToggle,
                  })}
                  secondaryLabel='Show original song this was remixed from'
                  tooltipText={
                    isOwnRemix
                      ? 'Is this song a Remix of another song of yours? This lets you select a previous song in your creation process and attribute it on this song.'
                      : 'This is a Remix of another song so Remix Origin will be displayed'
                  }
                  disabled={!isOwnRemix}
                />
              )}
              <ModalNavigationLabel
                label='Edit Displayed Lyrics'
                onClick={() => navigateTo('lyrics')}
                iconStart={LyricsIcon}
                className={`${
                  parentClip || showContestToggle
                    ? 'rounded-t-none border-t-0'
                    : 'rounded-t-md'
                } rounded-b-none before:border-b-0`}
              />
              <ModalNavigationLabel
                label='More Options'
                onClick={() => navigateTo('moreOptions')}
                iconStart={GearIcon}
                className='rounded-t-none rounded-b-md'
              />
            </div>
          )}
        </div>
      </div>
    );
  }
);

export default PublishModalEditClipSection;
