/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import { Modal, ModalContent, ModalProps } from '@chakra-ui/react';
import clsx from 'clsx';
import { observer } from 'mobx-react-lite';
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import CreateFormContext from '@/app/(root)/create/v2/CreateFormContext';
import { getCurrentLyrics } from '@/app/(root)/create/v2/actions/currentModeSetters';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import { useContextSelector } from '@/hooks/useContextSelector';
import useLyricsABFlow from '@/hooks/useLyricsABFlow';
import useLyricsABFlowTracking, {
  useLogLyricsViewedOnMount,
} from '@/hooks/useLyricsABFlowTracking';
import { CloseIcon, DiceIcon, EditIcon, FourStarIcon } from '@/icons';

import LyricsModelSelector from '../select/LyricsModelSelector';
import SpinnerSVG from '../svg/SpinnerSVG';
import TextareaV2 from '../textarea/TextareaV2';

const LyricsTitle: React.FC<{ children: React.ReactNode }> = ({ children }) => (
  <h4 className='grow-0 font-serif text-3xl'>{children}</h4>
);

const LyricsScrollableContent: React.FC<{
  id: string;
  requestId: string;
  text: string;
  title?: string;
}> = ({ id, requestId, text, title }) => {
  useLogLyricsViewedOnMount(id, requestId);

  return (
    <div className='tertiary-inner-vertical-fade h-full overflow-auto'>
      {title && <h4 className='text-md mt-4 opacity-50'>{title}</h4>}
      <div className='pt-4 pb-20 text-sm whitespace-pre-wrap text-foreground-tertiary'>
        {text.split('\n').map((line, i) => (
          <p key={i}>{line || <>&nbsp;</>}</p>
        ))}
      </div>
    </div>
  );
};

const LyricsFooter: React.FC<{ onAccept: () => void }> = ({ onAccept }) => (
  <div className='flex grow-0 items-center justify-center py-4'>
    <Button
      size={ButtonSize.Small}
      shape={ButtonShape.Pill}
      variant={ButtonVariant.Secondary}
      onClick={onAccept}
      className='px-8'
    >
      Select This Option
    </Button>
  </div>
);

const LyricsPresentation = ({
  id,
  requestId,
  title,
  text,
  onAccept,
  borderLeft,
}: {
  id: string;
  requestId: string;
  title: string;
  text: string;
  onAccept: () => void;
  borderLeft?: boolean;
}) => {
  return (
    <div className='align-stretch relative flex min-h-0 flex-col justify-stretch p-6 pb-0'>
      {borderLeft && (
        <div className='absolute top-2 bottom-6 left-0 w-px bg-quaternary' />
      )}
      <LyricsTitle>{title}</LyricsTitle>
      <LyricsScrollableContent id={id} requestId={requestId} text={text} />
      <LyricsFooter onAccept={onAccept} />
    </div>
  );
};

const LyricsSideBySide = ({
  lyricsA,
  lyricsB,
  requestId,
  handleAcceptLyrics,
}: {
  lyricsA?: { text: string; title: string; id: string };
  lyricsB?: { text: string; title: string; id: string };
  requestId: string;
  handleAcceptLyrics: (
    requestId: string,
    lyrics: { text: string; title: string; id: string }
  ) => void;
}) => {
  const { logLyricsAccepted } = useLyricsABFlowTracking();
  return (
    <>
      {lyricsA?.text ? (
        <LyricsPresentation
          id={lyricsA.id}
          requestId={requestId}
          title={lyricsA.title}
          text={lyricsA.text}
          onAccept={() => {
            handleAcceptLyrics(requestId, lyricsA);
            logLyricsAccepted(requestId, lyricsA.id);
          }}
        />
      ) : (
        <div className='flex items-center justify-center'>
          <SpinnerSVG />
        </div>
      )}
      {lyricsB?.text ? (
        <LyricsPresentation
          borderLeft
          id={lyricsB.id}
          requestId={requestId}
          title={lyricsB.title}
          text={lyricsB.text}
          onAccept={() => {
            handleAcceptLyrics(requestId, lyricsB);
            logLyricsAccepted(requestId, lyricsB.id);
          }}
        />
      ) : (
        <div className='flex items-center justify-center'>
          <SpinnerSVG />
        </div>
      )}
    </>
  );
};

const LyricsMobileTabs = ({
  lyricsA,
  lyricsB,
  requestId,
  mobileTab,
  setMobileTab,
  handleAcceptLyrics,
}: {
  lyricsA?: { text: string; title: string; id: string };
  lyricsB?: { text: string; title: string; id: string };
  requestId: string;
  mobileTab: 'a' | 'b';
  setMobileTab: (tab: 'a' | 'b') => void;
  handleAcceptLyrics: (
    requestId: string,
    lyrics: { text: string; title: string; id: string }
  ) => void;
}) => {
  const selectedLyrics = mobileTab === 'a' ? lyricsA : lyricsB;
  const { logMobileOptionTabClick, logLyricsAccepted } =
    useLyricsABFlowTracking();
  return lyricsA?.text && lyricsB?.text ? (
    <>
      <div className='col-span-full flex items-stretch gap-2 pt-2'>
        <div
          className={clsx(
            'w-[50%] shrink-1 grow-0 overflow-hidden border-b border-b-quaternary bg-background-secondary p-2 text-ellipsis whitespace-nowrap text-foreground-tertiary',
            { 'border-b-white text-foreground-primary': mobileTab === 'a' }
          )}
          onClick={() => {
            setMobileTab('a');
            logMobileOptionTabClick(lyricsA.id);
          }}
        >
          {lyricsA.title}
        </div>
        <div
          className={clsx(
            'w-[50%] shrink-1 grow-0 overflow-hidden border-b border-b-quaternary bg-background-secondary p-2 text-ellipsis whitespace-nowrap text-foreground-tertiary',
            { 'border-b-white text-foreground-primary': mobileTab === 'b' }
          )}
          onClick={() => {
            setMobileTab('b');
            logMobileOptionTabClick(lyricsB.id);
          }}
        >
          {lyricsB.title}
        </div>
      </div>
      {selectedLyrics && (
        <div className='align-stretch col-span-full flex min-h-0 flex-col justify-stretch px-2'>
          <LyricsScrollableContent
            requestId={requestId}
            id={selectedLyrics.id}
            title={selectedLyrics.title}
            text={selectedLyrics.text}
          />
          <LyricsFooter
            onAccept={() => {
              handleAcceptLyrics(requestId, selectedLyrics);
              logLyricsAccepted(requestId, selectedLyrics.id);
            }}
          />
        </div>
      )}
    </>
  ) : (
    <>
      <div className='col-span-full flex min-h-0 items-center justify-center'>
        <SpinnerSVG />
      </div>
      <div className='col-span-full' />
    </>
  );
};

const LyricsPromptInput = ({
  lyricsABFlow,
  onClose,
}: {
  lyricsABFlow: ReturnType<typeof useLyricsABFlow>;
  onClose: () => void;
}) => {
  const {
    prompt,
    setPrompt,
    lyricsModel,
    setLyricsModel,
    lyricsA,
    lyricsB,
    rejectLyricsIfNoneAccepted,
    requestId,
    generate,
    generating,
    cancel,
  } = lyricsABFlow;

  const lyricsABFlowTracking = useLyricsABFlowTracking();

  const buttonCopy = useMemo(() => {
    if (generating) return 'Writing...';
    return 'Write Lyrics';
  }, [generating]);

  return (
    <div className='flex flex-1 items-center justify-center'>
      <div className='relative w-full max-w-[560px] rounded-md bg-background-tertiary pb-10 duration-300'>
        <TextareaV2
          autoFocus
          value={prompt}
          maxLength={200}
          disabled={generating}
          onChange={(e) => setPrompt(e.target.value)}
          placeholder={
            'Describe the lyrics you want, or share a theme or topic.'
          }
          rows={2}
          onKeyDown={(e) => {
            if (e.key === 'Escape') {
              if (!generating) {
                onClose();
                cancel();
                if (lyricsA && lyricsB && requestId) {
                  rejectLyricsIfNoneAccepted(requestId);
                }
                lyricsABFlowTracking.logEscapeKey(requestId);
              }
            } else if (e.key === 'Enter') {
              e.preventDefault();
              if (!generating) {
                generate();
              }
              if (lyricsA && lyricsB && requestId) {
                rejectLyricsIfNoneAccepted(requestId);
              }
              lyricsABFlowTracking.logEnterKey();
            }
          }}
          className='border-0 pr-8 pb-2 pl-5'
        />
        <FourStarIcon className='absolute top-5 left-3 h-3 w-3 text-accent-pink' />

        <div
          className={
            'absolute right-0 bottom-0 left-0 flex justify-between p-2 align-middle'
          }
        >
          {generating ? (
            <Button
              size={ButtonSize.Small}
              shape={ButtonShape.Pill}
              variant={ButtonVariant.Secondary}
              onClick={() => {
                cancel();
                lyricsABFlowTracking.logCancelButton(requestId);
              }}
              className='pr-8 pl-8'
            >
              Cancel
            </Button>
          ) : (
            <LyricsModelSelector
              size={ButtonSize.Small}
              value={lyricsModel}
              onSetValue={(newLyricsModel) => {
                setLyricsModel(newLyricsModel);
                lyricsABFlowTracking.logModelSelectorClick(newLyricsModel);
              }}
              disabled={generating}
            />
          )}
          <Button
            size={ButtonSize.Small}
            shape={ButtonShape.Pill}
            variant={ButtonVariant.DarkPrimary}
            disabled={generating}
            onClick={() => {
              generate();
              if (lyricsA && lyricsB && requestId) {
                rejectLyricsIfNoneAccepted(requestId);
              }
              lyricsABFlowTracking.logGenerateButtonClick(
                prompt,
                lyricsModel,
                requestId
              );
            }}
            className='relative whitespace-nowrap'
            icon={
              generating ? (
                <SpinnerSVG width={18} height={18} />
              ) : prompt.length === 0 ? (
                <DiceIcon className='text-foreground-on-dark h-3 w-3' />
              ) : (
                <EditIcon className='text-foreground-on-dark h-3 w-3' />
              )
            }
          >
            {buttonCopy}
          </Button>
        </div>
      </div>
    </div>
  );
};

// this needs to be wrapped in `observer` because some of the hooks it calls expect to be able to reach the global stores
const LyricsCowriteModal = observer(
  (
    props: Omit<ModalProps, 'children'> & {
      lyricsABFlow?: ReturnType<typeof useLyricsABFlow>;
    }
  ) => {
    const lyricsABFlow = props.lyricsABFlow || useLyricsABFlow();
    const lyricsABFlowTracking = useLyricsABFlowTracking();

    const {
      cancel,
      lyricsA,
      lyricsB,
      setLyricsADisplayed,
      setLyricsBDisplayed,
      rejectLyricsIfNoneAccepted,
      handleAcceptLyrics,
      requestId,
    } = lyricsABFlow;

    const isMobile = !useBreakpointMd();
    const [mobileTab, setMobileTab] = useState<'a' | 'b'>('a');

    useEffect(() => {
      if (lyricsA?.text && (!isMobile || (isMobile && mobileTab === 'a'))) {
        setLyricsADisplayed(true);
      } else if (!lyricsA?.text) {
        setLyricsADisplayed(false);
      }

      if (lyricsB?.text && (!isMobile || (isMobile && mobileTab === 'b'))) {
        setLyricsBDisplayed(true);
      } else if (!lyricsB?.text) {
        setLyricsBDisplayed(false);
      }
    }, [
      isMobile,
      lyricsA,
      lyricsB,
      mobileTab,
      setLyricsADisplayed,
      setLyricsBDisplayed,
    ]);

    const acceptLyricsAndClose = useCallback(
      (
        requestId: string,
        lyrics: { text: string; title: string; id: string }
      ) => {
        handleAcceptLyrics(requestId, lyrics);
        props.onClose();
      },
      [handleAcceptLyrics, props.onClose]
    );

    const createV2Lyrics = useContextSelector(CreateFormContext, (ctx) =>
      ctx ? getCurrentLyrics(ctx.state) : null
    );

    const wasOpen = useRef(props.isOpen);
    useEffect(() => {
      if (
        props.isOpen &&
        !wasOpen.current &&
        !!createV2Lyrics &&
        createV2Lyrics.length <= 200
      ) {
        lyricsABFlow.setPrompt(createV2Lyrics);
      }
      wasOpen.current = props.isOpen;
    }, [props.isOpen, createV2Lyrics, lyricsABFlow]);

    return (
      <Modal {...props} size='4xl'>
        <div className='fixed inset-0 z-1400 bg-background-primary/80' />
        <ModalContent
          marginTop={isMobile ? '0' : undefined}
          marginBottom={isMobile ? '0' : undefined}
          overflow='hidden'
          height={isMobile ? '100svh' : 'calc(100vh - 130px)'}
        >
          <Button
            variant={ButtonVariant.Tertiary}
            size={ButtonSize.Mini}
            shape={ButtonShape.Rectangle}
            className={clsx('absolute z-10 rounded-lg py-2', {
              ['top-2 right-2']: isMobile,
              ['top-1 right-1']: !isMobile,
            })}
            onClick={() => {
              props.onClose();
              cancel();
              if (lyricsA && lyricsB && requestId) {
                rejectLyricsIfNoneAccepted(requestId);
              }
              lyricsABFlowTracking.logLyricsModalClose(requestId);
            }}
          >
            <CloseIcon className='text-foreground-secondary' />
          </Button>
          <div className='absolute top-0 bottom-0 left-0 grid min-h-0 w-[200%] grid-cols-2 overflow-hidden transition-all'>
            <div
              className='grid min-h-0 grid-cols-2 bg-background-secondary p-3 text-foreground-primary'
              style={{
                gridTemplateRows: isMobile ? 'auto 1fr' : '1fr auto',
              }}
            >
              {!isMobile &&
                (!!requestId ? (
                  <LyricsSideBySide
                    lyricsA={lyricsA}
                    lyricsB={lyricsB}
                    handleAcceptLyrics={acceptLyricsAndClose}
                    requestId={requestId}
                  />
                ) : (
                  <div className='col-span-2 flex flex-col items-center justify-center text-foreground-secondary'>
                    <p>Enter a prompt below to generate lyrics.</p>
                  </div>
                ))}

              <div className='col-span-full flex items-end justify-between'>
                <LyricsPromptInput
                  lyricsABFlow={lyricsABFlow}
                  onClose={props.onClose}
                />
              </div>

              {isMobile &&
                (!!requestId ? (
                  <LyricsMobileTabs
                    lyricsA={lyricsA}
                    lyricsB={lyricsB}
                    requestId={requestId}
                    handleAcceptLyrics={acceptLyricsAndClose}
                    mobileTab={mobileTab}
                    setMobileTab={setMobileTab}
                  />
                ) : (
                  <div />
                ))}
            </div>
          </div>
        </ModalContent>
      </Modal>
    );
  }
);
export default LyricsCowriteModal;
