'use client';

/* eslint jsx-a11y/label-has-associated-control: warn */
import { useGateValue } from '@statsig/react-bindings';
import clsx from 'clsx';
import { usePathname } from 'next/navigation';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { IMask, IMaskInput } from 'react-imask';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import Modal from '@/components/modal/Modal';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import { useModalContext } from '@/context/ModalContext';
import {
  ArrowLeftIcon,
  CheckIcon,
  CopyIcon,
  EmbedIcon,
  FacebookIcon,
  LinkIcon,
  LinkedinIcon,
  MailIcon,
  RedditIcon,
  TwitterXIcon,
} from '@/icons';
import { useApiClient } from '@/lib/apiClient';
import { ShareModalContext } from '@/logging/eventTypes/ShareModalEventType';
import logWebUserEvent from '@/logging/logWebUserEvent';
import {
  EmbedIframeOptions,
  generateEmbedCode,
  generateEmbedUrl,
  generateLinkUrl,
  generateUrlWithParams,
} from '@/utils/embeds';
import { eventLogger } from '@/utils/event-logger';
import { ActionName } from '@/utils/event-names';
import { getShareLink } from '@/utils/share';

enum PlatformNames {
  facebook = 'facebook',
  reddit = 'reddit',
  x = 'x',
  linkedin = 'linkedin',
  email = 'email',
  instagram = 'instagram',
}

const SwatchButton: React.FC<React.ComponentProps<typeof Button>> = (props) => (
  <Button
    variant={ButtonVariant.Inherit}
    size={ButtonSize.Large}
    shape={ButtonShape.Pill}
    aspectSquare
    {...props}
    className={twMerge(
      clsx(
        'bg-linear-to-t from-transparent to-transparent after:border-2',
        'opacity-100 after:opacity-100',
        {
          'after:border-white after:shadow-swatch-outline': props.active,
          'after:border-transparent': !props.active,
        }
      ),
      props.className
    )}
  />
);

const ShareModal: React.FC = () => {
  const { session, playbar, clips } = useStores();
  const { closeModal, getModalData, getModalSource } = useModalContext();

  // Get modal data and source
  const modalData = getModalData(ModalTypes.SHARE_CLIP);
  const modalSource = getModalSource(ModalTypes.SHARE_CLIP);

  // Get the clip from the clipId or use the provided profile data
  const song = modalData?.clipId ? clips.clipById[modalData.clipId] : undefined;
  const profileHandle = modalData?.profileHandle;
  const clipDuration = useMemo(
    () =>
      playbar.clip?.id && clips.clipById[playbar.clip.id]
        ? clips.clipById[playbar.clip.id]?.metadata?.duration
        : null,
    [playbar.clip?.id, clips.clipById]
  );
  const pathname = usePathname();
  const apiClient = useApiClient();
  const { t } = useTranslation();

  const showShareCustomization = useGateValue('embed-customization');

  const [embedOptions, setEmbedOptions] = useState<EmbedIframeOptions>({
    width: 760,
    height: 240,
  });

  const [shouldShareTime, setShouldShareTime] = useState(false);
  const [isShowEmbed, setIsShowEmbed] = useState(false);

  const incrementShareCount = useCallback(
    (clipId: string, sharePlatform: string) => {
      apiClient.POST('/api/gen/{gen_id}/increment_action_count/', {
        params: { path: { gen_id: clipId } },
        body: {
          action: 'share',
          share_platform: sharePlatform,
        },
      });
    },
    [apiClient]
  );

  const getShareUrl = useCallback(
    async (sharePlatform?: string, currentTime?: number): Promise<string> => {
      if (song) {
        const shareLink = await getShareLink({
          apiClient,
          contentType: 'song',
          contentId: song.id,
          platform: sharePlatform,
        });
        const url = new URL(shareLink || generateLinkUrl(song.id, 'song'));
        if (currentTime) {
          url.searchParams.set('time', currentTime.toString());
        }
        return url.toString();
      }
      if (profileHandle) {
        return generateLinkUrl(profileHandle, 'profile');
      }
      return '';
    },
    [song, profileHandle, apiClient]
  );

  const [copySuccess, setCopySuccess] = useState(false);

  useEffect(() => {
    if (copySuccess === true) {
      const timeout = setTimeout(() => {
        setCopySuccess(false);
      }, 2000);
      return () => {
        clearTimeout(timeout);
      };
    }
  }, [copySuccess]);

  const [embedUrl, embedCode] = useMemo(() => {
    if (!song) {
      return ['', ''];
    }
    const { width, height, ...urlOptions } = embedOptions;
    return [
      generateEmbedUrl(song.id, 'song', urlOptions),
      generateEmbedCode(song.id, 'song', embedOptions),
    ];
  }, [song, embedOptions]);

  const convertSecondsToTimestamp = (seconds: number) => {
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = Math.floor(seconds % 60);
    const timestamp = `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
    if (timestamp.length > 4) {
      return '0:00'; // fails, fallback to 0:00
    }
    return timestamp;
  };
  const convertTimestampToSeconds = (timestamp: string) => {
    const [minutes, seconds] = timestamp.split(':').map(Number);
    return minutes * 60 + seconds;
  };
  const [timestampValue, setTimestampValue] = useState('0:00');

  const handleCopyLinkClick = useCallback(
    async (currentTime?: number) => {
      if (
        navigator.clipboard &&
        window.isSecureContext &&
        (song || profileHandle)
      ) {
        logWebUserEvent({
          actionName: 'ShareModalCopyLinkClicked',
          context: song
            ? {
                clipId: song?.id || '',
                source: modalSource,
                timestamp: shouldShareTime ? timestampValue : undefined,
              }
            : {
                profileHandle: profileHandle || '',
                source: modalSource,
              },
        });
        const shareUrl: string = await getShareUrl(undefined, currentTime);
        navigator.clipboard
          .writeText(shareUrl)
          .then(() => {
            setCopySuccess(true);
          })
          .catch((err) => {
            console.error('Failed to copy: ', err);
          });
      }
    },
    [
      getShareUrl,
      timestampValue,
      shouldShareTime,
      song,
      profileHandle,
      modalSource,
    ]
  );

  const handleShareClick = useCallback(
    async ({
      shareUrl,
      actionName,
      platformName,
      openWindowFeatures = 'width=600,height=300',
    }: {
      shareUrl: string;
      actionName: string;
      platformName: PlatformNames;
      openWindowFeatures?: string | false;
    }) => {
      if (openWindowFeatures !== false) {
        window.open(shareUrl, '_blank', openWindowFeatures);
      } else {
        window.location.href = shareUrl;
      }
      if (song || profileHandle) {
        const context = song
          ? {
              clipId: song.id || '',
              source: modalSource,
              platformName,
              timestamp: shouldShareTime ? timestampValue : undefined,
            }
          : {
              profileHandle: profileHandle || '',
              source: modalSource,
              platformName,
            };
        logWebUserEvent({
          actionName: 'ShareModalShareClicked',
          context,
        });
      }
      eventLogger.logAudioActionEvent(
        true,
        actionName,
        song!,
        session,
        pathname
      );
      if (song?.id) {
        incrementShareCount(song?.id, platformName);
      }
    },
    [
      pathname,
      session,
      song,
      profileHandle,
      timestampValue,
      shouldShareTime,
      modalSource,
      incrementShareCount,
    ]
  );

  const handleCopyEmbedClick = useCallback(() => {
    if (navigator.clipboard && window.isSecureContext && song) {
      logWebUserEvent({
        actionName: 'ShareModalEmbedClicked',
        context: {
          clipId: song.id,
          source: modalSource,
        },
      });
      navigator.clipboard
        .writeText(embedCode)
        .then(() => {
          setCopySuccess(true);
        })
        .catch((err) => {
          console.error('Failed to copy: ', err);
        });
    }
  }, [embedCode, song, modalSource]);

  useEffect(() => {
    if (song || profileHandle) {
      const playbarTimestamp = convertSecondsToTimestamp(
        playbar.getCurrentTime() ?? playbar.currentTime ?? 0
      );
      setTimestampValue(playbarTimestamp);

      const context = song
        ? {
            clipId: song.id || '',
            source: modalSource,
          }
        : ({
            profileHandle: profileHandle || '',
            source: modalSource,
          } satisfies ShareModalContext);
      logWebUserEvent({
        actionName: 'ShareModalOpened',
        context,
      });
    }
  }, [song, profileHandle, modalSource]);

  const [linkUrl, setLinkUrl] = useState('');

  useEffect(() => {
    const updateUrl = async () => {
      const url = await getShareUrl(
        undefined,
        shouldShareTime ? convertTimestampToSeconds(timestampValue) : undefined
      );
      setLinkUrl(url);
    };
    updateUrl();
  }, [getShareUrl, shouldShareTime, timestampValue, song, profileHandle]);

  const handleClose = useCallback(() => {
    if (song || profileHandle) {
      logWebUserEvent({
        actionName: 'ShareModalClosed',
        context: song
          ? {
              clipId: song?.id || '',
              source: modalSource,
            }
          : {
              profileHandle: profileHandle || '',
              source: modalSource,
            },
      });
    }
    closeModal(ModalTypes.SHARE_CLIP);
  }, [song, profileHandle, modalSource, closeModal]);

  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        e.preventDefault();
        e.stopPropagation();
        handleClose();
      }
    };
    window.addEventListener('keydown', handleEscape, true);
    return () => window.removeEventListener('keydown', handleEscape, true);
  }, [handleClose]);

  const currentTime = shouldShareTime
    ? convertTimestampToSeconds(timestampValue)
    : undefined;

  return (
    <Modal
      title='Share to...'
      titleClassName='text-2xl font-sans font-semibold pt-4 flex-1 text-center'
      closeButtonClasses='absolute right-4 top-4 w-12 h-12'
      onClose={handleClose}
      className='overflow-auto'
      contentWrapperClasses='w-[90%]'
      wrapperClasses='-mx-6'
      width={800}
    >
      {/* min height is janky */}
      <div className='flex flex-col p-8'>
        {!isShowEmbed && (
          <div className='mx-auto flex w-full max-w-[630px] flex-1 flex-col items-stretch justify-center gap-2 px-4'>
            <div className='flex flex-row flex-wrap items-center justify-center gap-4 md:gap-6'>
              <div className='flex flex-col items-center'>
                <Button
                  className='h-16 w-16 hover:bg-black hover:text-white'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.x,
                      currentTime
                    );
                    await handleShareClick({
                      shareUrl: generateUrlWithParams(
                        'https://twitter.com/intent/tweet',
                        {
                          url: shareUrl,
                          text: 'Listen and make your own song with Suno.',
                        }
                      ),
                      actionName: ActionName.shareSongWithX,
                      platformName: PlatformNames.x,
                    });
                  }}
                  icon={TwitterXIcon}
                  title='X'
                  aria-label='X'
                />
                <div className='mt-2 text-sm'>X</div>
              </div>
              <div className='flex flex-col items-center'>
                <Button
                  className='h-16 w-16 hover:bg-[#1877f2] hover:text-white'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.facebook,
                      currentTime
                    );
                    handleShareClick({
                      shareUrl: generateUrlWithParams(
                        'https://www.facebook.com/sharer/sharer.php',
                        {
                          u: shareUrl,
                          quote: 'Listen and make your own song with Suno.',
                        }
                      ),
                      actionName: ActionName.shareSongWithFacebook,
                      platformName: PlatformNames.facebook,
                    });
                  }}
                  icon={FacebookIcon}
                  title='Facebook'
                  aria-label='Facebook'
                />
                <div className='mt-2 text-sm'>Facebook</div>
              </div>
              {/* Instagram does not have a share feature. UI is ready though.*/}
              {/*              <div className='flex flex-col items-center'>
                <Button
                  className='hover:bg-[#E1306C] hover:text-white w-16 h-16'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.instagram,
                      currentTime
                    );
                    handleShareClick({
                      shareUrl: generateUrlWithParams(
                        'https://www.instagram.com/share',
                        {
                          url: shareUrl,
                          caption: 'Listen and make your own song with Suno.',
                        }
                      ),
                      actionName: ActionName.shareSongWithInstagram,
                      platformName: PlatformNames.instagram,
                    });
                  }}
                  icon={InstagramIcon}
                  title='Instagram'
                  aria-label='Instagram'
                />
                <div className='mt-2 text-sm'>Instagram</div>
              </div> */}
              <div className='flex flex-col items-center'>
                <Button
                  className='h-16 w-16 hover:bg-[#0072b1] hover:text-white'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.linkedin,
                      currentTime
                    );
                    handleShareClick({
                      shareUrl: generateUrlWithParams(
                        'https://www.linkedin.com/sharing/share-offsite/',
                        {
                          url: shareUrl,
                          title: 'Listen and make your own song with Suno.',
                        }
                      ),
                      actionName: ActionName.shareSongWithLinkedIn,
                      platformName: PlatformNames.linkedin,
                    });
                  }}
                  icon={LinkedinIcon}
                  title='LinkedIn'
                  aria-label='LinkedIn'
                />
                <div className='mt-2 text-sm'>LinkedIn</div>
              </div>
              <div className='flex flex-col items-center'>
                <Button
                  className='h-16 w-16 hover:bg-[#ff5700] hover:text-white'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.reddit,
                      currentTime
                    );
                    handleShareClick({
                      shareUrl: generateUrlWithParams(
                        'https://reddit.com/submit',
                        {
                          url: shareUrl,
                          title: 'Listen and make your own song with Suno',
                        }
                      ),
                      actionName: ActionName.shareSongWithReddit,
                      platformName: PlatformNames.reddit,
                    });
                  }}
                  icon={RedditIcon}
                  title='Reddit'
                  aria-label='Reddit'
                />
                <div className='mt-2 text-sm'>Reddit</div>
              </div>
              <div className='flex flex-col items-center'>
                <Button
                  className='h-16 w-16'
                  contentClassName='justify-center'
                  size={ButtonSize.Large}
                  shape={ButtonShape.Pill}
                  aspectSquare
                  onClick={async () => {
                    const shareUrl: string = await getShareUrl(
                      PlatformNames.email,
                      currentTime
                    );
                    handleShareClick({
                      shareUrl: generateUrlWithParams('mailto:', {
                        subject: 'Check out this song!',
                        body: `Hi there,\n\nCheck out this song on Suno here! ${shareUrl}\n\n`,
                      }),
                      actionName: ActionName.shareSongWithEmail,
                      openWindowFeatures: false,
                      platformName: PlatformNames.email,
                    });
                  }}
                  icon={MailIcon}
                  title='Email'
                  aria-label='Email'
                />
                <div className='mt-2 text-sm'>Email</div>
              </div>
              {song && (
                <div className='flex flex-col items-center'>
                  <Button
                    className='h-16 w-16'
                    contentClassName='justify-center'
                    size={ButtonSize.Large}
                    shape={ButtonShape.Pill}
                    aspectSquare
                    onClick={() => setIsShowEmbed(true)}
                    icon={EmbedIcon}
                    title='Embed'
                    aria-label='Embed'
                  />
                  <div className='mt-2 text-sm'>Embed</div>
                </div>
              )}
            </div>
            <div className='mt-8 mb-4 flex w-full gap-4 overflow-hidden rounded-2xl border border-border-primary bg-background-primary p-4 px-6'>
              <div className='flex flex-1 items-center truncate py-3 text-sm'>
                <LinkIcon className='mr-3 h-6 w-6 shrink-0' />
                <span className='truncate'>{linkUrl}</span>
              </div>
              <Button
                className='rounded-full px-5'
                variant={ButtonVariant.Primary}
                shape={ButtonShape.Pill}
                onClick={async () => {
                  await handleCopyLinkClick(
                    shouldShareTime
                      ? convertTimestampToSeconds(timestampValue)
                      : undefined
                  );
                }}
                icon={copySuccess ? CheckIcon : CopyIcon}
              >
                {t('cta.copy')}
              </Button>
            </div>
            {song && (
              <div
                className={clsx(
                  'flex flex-row items-center justify-center gap-2',
                  'font-sans text-sm font-normal',
                  {
                    'text-foreground-inactive': !shouldShareTime,
                  }
                )}
              >
                <input
                  type='checkbox'
                  checked={shouldShareTime}
                  onChange={(e) => setShouldShareTime(e.target.checked)}
                  className='h-4 w-4 rounded border-border-primary focus:ring-2 focus:ring-dodger-blue-300'
                />
                <div>Start song at</div>
                <IMaskInput
                  mask='M:SS'
                  lazy={false}
                  overwrite={true}
                  placeholderChar='_'
                  value={timestampValue}
                  onAccept={(value) => {
                    setTimestampValue(value);
                  }}
                  onBlur={() => {
                    const formattedValue = timestampValue.replace(/_/g, '0');
                    const playbarDuration = Math.floor(
                      clipDuration ? clipDuration : 0
                    );
                    const currentTimeSeconds =
                      convertTimestampToSeconds(formattedValue);
                    if (currentTimeSeconds > playbarDuration) {
                      setTimestampValue(
                        convertSecondsToTimestamp(playbarDuration)
                      );
                    } else {
                      setTimestampValue(formattedValue);
                    }
                  }}
                  className={clsx(
                    'w-20 rounded border px-2 py-1 text-center focus:outline-none',
                    'font-["Neue Montreal"] border-border-secondary font-normal text-inherit',
                    {
                      'bg-background-secondary': shouldShareTime,
                      'cursor-not-allowed bg-transparent': !shouldShareTime,
                    }
                  )}
                  disabled={!shouldShareTime}
                  blocks={{
                    M: {
                      mask: '0',
                    },
                    SS: {
                      mask: IMask.MaskedRange,
                      from: 0,
                      to: 59,
                    },
                  }}
                />
              </div>
            )}
          </div>
        )}
        {isShowEmbed && (
          <div className='flex flex-1 flex-col items-stretch justify-start gap-4'>
            {showShareCustomization && (
              <div className='flex flex-row gap-4'>
                <div className='flex flex-1 flex-row items-center justify-start gap-2'>
                  <div className='font-sans text-sm font-semibold'>Color:</div>
                  <SwatchButton
                    className='from-[#1e2960] to-[#1c1c1c]'
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        theme: undefined,
                      }))
                    }
                    active={!embedOptions.theme}
                    title='Light'
                  />
                  <SwatchButton
                    className='theme-dark from-background-secondary to-background-primary'
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        theme: 'dark',
                      }))
                    }
                    active={embedOptions.theme === 'dark'}
                    title='Dark'
                  />
                  <SwatchButton
                    className='theme-light from-background-secondary to-background-primary'
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        theme: 'light',
                      }))
                    }
                    active={embedOptions.theme === 'light'}
                    title='Light'
                  />
                </div>
                <div className='flex flex-row items-center justify-end gap-2 max-sm:hidden'>
                  <div className='font-sans text-sm font-semibold'>Size:</div>
                  <Button
                    variant={ButtonVariant.Secondary}
                    size={ButtonSize.Small}
                    shape={ButtonShape.Pill}
                    active={
                      embedOptions.width === 760 && embedOptions.height === 240
                    }
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        width: 760,
                        height: 240,
                      }))
                    }
                  >
                    Standard
                  </Button>
                  <Button
                    variant={ButtonVariant.Secondary}
                    size={ButtonSize.Small}
                    shape={ButtonShape.Pill}
                    active={embedOptions.height === 140}
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        width: 600,
                        height: 140,
                      }))
                    }
                  >
                    Small
                  </Button>
                  <Button
                    variant={ButtonVariant.Secondary}
                    size={ButtonSize.Small}
                    shape={ButtonShape.Pill}
                    active={embedOptions.width === 300}
                    onClick={() =>
                      setEmbedOptions((prevEmbedOptions) => ({
                        ...prevEmbedOptions,
                        width: 300,
                        height: 400,
                      }))
                    }
                  >
                    Card
                  </Button>
                </div>
              </div>
            )}
            {song ? (
              <div className='flex-1'>
                <iframe
                  className='mx-auto mb-4 box-content max-w-full rounded-md border border-border-secondary'
                  src={embedUrl}
                  width={embedOptions.width}
                  height={embedOptions.height}
                  title='Embed preview'
                ></iframe>
              </div>
            ) : null}
            <div className='mt-4 mb-4 flex w-full items-center gap-4 overflow-hidden rounded-2xl border border-border-primary bg-background-primary p-4 px-6'>
              <div className='flex flex-1 items-center py-3 text-xs'>
                <EmbedIcon className='mr-3 h-6 w-6 shrink-0' />
                <span className='font-mono break-all whitespace-pre-wrap'>
                  {embedCode}
                </span>
              </div>
              <Button
                className='rounded-full px-5'
                variant={ButtonVariant.Primary}
                shape={ButtonShape.Pill}
                onClick={handleCopyEmbedClick}
                icon={copySuccess ? CheckIcon : CopyIcon}
              >
                {t('cta.copy')}
              </Button>
            </div>
            <div className='flex flex-row items-center justify-center gap-2 px-2'>
              <Button
                variant={ButtonVariant.Tertiary}
                size={ButtonSize.Large}
                shape={ButtonShape.Pill}
                onClick={() => setIsShowEmbed(false)}
                icon={ArrowLeftIcon}
              >
                Go back
              </Button>
            </div>
          </div>
        )}
      </div>
    </Modal>
  );
};

export default ShareModal;
