import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { setIn } from 'lodash-redux-immutability';
import React, {
  Dispatch,
  SetStateAction,
  memo,
  useCallback,
  useContext,
  useRef,
} from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '@/components/contextMenu/ContextMenu';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  DiceIcon,
  MicrophoneIcon,
  PlusIcon,
  SuccessIcon,
  UploadIcon,
} from '@/icons';

import UploadStateContext from '../../uploaderV2/UploadStateContext';
import CreateFormContext from '../../v2/CreateFormContext';
import { CreateFormModals, CreateModes } from '../../v2/types';
import CreateCard from './CreateCard';
import CreateTextarea from './CreateTextarea';
import { CreateTheme, bigSpace, smallSpace } from './themes';
import useFileInput from './useFileInput';
import { usePromptPlaceholder } from './usePromptPlaceholder';
import useResizer, {
  RESIZABLE_CONTAINER_CLASS_NAME,
  ResizerHandle,
} from './useResizer';
import useSuggestedStyles from './useSuggestedStyles';

interface SongDescriptionCardProps {
  songDescription: string;
  setSongDescription: Dispatch<SetStateAction<string>>;

  onAddLyrics: () => void;
  onUploadFile: () => void;
  onClickRecordButton: () => void;

  songDescriptionInputHeight?: number;
  setSongDescriptionInputHeight?: Dispatch<SetStateAction<number>>;

  suggestedStyles: string[];
  suggestedStylesLoading?: boolean;
  onPickSuggestedStyle: (style: string) => void;

  instrumental: boolean;
  setInstrumental: Dispatch<SetStateAction<boolean>>;
}

const SongDescriptionContent = styled.div`
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 0;
  overflow: hidden;
`;

const TextareaWrapper = styled.div`
  flex-grow: 1;
  padding: 0 16px;
`;

const Footer = styled.div`
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  gap: ${smallSpace}px;
  padding-left: ${bigSpace}px;
  padding-right: ${bigSpace}px;
  padding-bottom: ${bigSpace}px;
  overflow-x: auto;
`;

const SubFooterTitle = styled.div`
  font-size: 14px;
  font-weight: 500;
  color: var(--color-foreground-inactive);
  padding: ${smallSpace}px 0 0 0;
  margin: 0 16px ${smallSpace}px 16px;
  border-top: 1px solid var(--color-border-primary);
`;

const SongDescriptionCard: React.FC<SongDescriptionCardProps> = memo(
  function SongDescriptionCard({
    songDescription,
    setSongDescription,

    onAddLyrics,
    onUploadFile,
    onClickRecordButton,

    songDescriptionInputHeight,
    setSongDescriptionInputHeight,

    suggestedStyles,
    suggestedStylesLoading,
    onPickSuggestedStyle,

    instrumental,
    setInstrumental,
  }) {
    const { session } = useStores();
    const textareaRef = useRef<HTMLTextAreaElement>(null);
    const { getPromptPlaceholder } = usePromptPlaceholder();
    const openFileInput = useFileInput({ onFileSelect: onUploadFile });

    const receiveResizerRef = useResizer({
      height: songDescriptionInputHeight ?? 120,
      setHeight: setSongDescriptionInputHeight,
      minHeight: 120,
      resizeTargetRef: textareaRef,
    });

    const theme = useTheme() as CreateTheme;

    return (
      <CreateCard
        className={RESIZABLE_CONTAINER_CLASS_NAME}
        title='Song Description'
        headerContent={
          <>
            <Button
              shape={ButtonShape.Pill}
              className={theme.tailwind.bigButtonPadding}
              icon={<DiceIcon className='h-4 w-4' />}
              aria-label='Generate random song description'
              onClick={() => {
                setSongDescription(getPromptPlaceholder() ?? songDescription);

                // Log and clear dice tooltip when clicked
                session.logCreateOnboardingStepMounted('dice_tooltip');
                session.clearTooltipOnDice();
              }}
            />
          </>
        }
      >
        <SongDescriptionContent>
          <TextareaWrapper>
            <CreateTextarea
              ref={textareaRef}
              value={songDescription}
              onChange={(e) => setSongDescription(e.target.value)}
              placeholder='Hip-hop, R&B, upbeat'
              className='mb-0 pb-0'
            />
          </TextareaWrapper>
          <Footer>
            <div className='flex grow flex-row gap-2'>
              <ContextMenuTrigger
                placement='top-right'
                ButtonComponent={(props) => (
                  <Button
                    shape={ButtonShape.Pill}
                    variant={ButtonVariant.Standard}
                    className='py-2 pr-3 pl-2 text-xs'
                    {...props}
                  >
                    <PlusIcon className='h-5 w-5 scale-75' />
                    Audio
                  </Button>
                )}
                ContentsComponent={({ onClose }: { onClose: () => void }) => (
                  <>
                    <ContextMenuItem
                      onClick={() => {
                        openFileInput();
                        onClose();
                      }}
                      icon={<UploadIcon />}
                    >
                      Upload
                    </ContextMenuItem>
                    <ContextMenuItem
                      onClick={() => {
                        onClickRecordButton();
                        onClose();
                      }}
                      icon={<MicrophoneIcon />}
                    >
                      Record
                    </ContextMenuItem>
                  </>
                )}
              />

              <Button
                shape={ButtonShape.Pill}
                variant={ButtonVariant.Standard}
                onClick={onAddLyrics}
                className='py-2 pr-3 pl-2 text-xs'
              >
                <PlusIcon className='h-5 w-5 scale-75' />
                Lyrics
              </Button>
            </div>

            <Button
              shape={ButtonShape.Pill}
              variant={
                instrumental ? ButtonVariant.Primary : ButtonVariant.Secondary
              }
              icon={
                <SuccessIcon
                  className={`h-5 w-5 ${instrumental ? 'text-pink-500' : 'text-background-tertiary'}`}
                />
              }
              className='py-2 pr-4 pl-2 text-xs'
              aria-label={
                instrumental
                  ? 'Disable instrumental mode'
                  : 'Enable instrumental mode'
              }
              onClick={() => setInstrumental(!instrumental)}
            >
              Instrumental
            </Button>
          </Footer>
          <SubFooterTitle>Inspiration</SubFooterTitle>
          <Footer>
            {suggestedStyles.map((style, index) => (
              <Button
                key={`${style}-${index}`}
                shape={ButtonShape.Pill}
                variant={ButtonVariant.Standard}
                onClick={() => onPickSuggestedStyle(style)}
                className='py-2 pr-3 pl-2 text-xs whitespace-nowrap'
              >
                <PlusIcon className='h-5 w-5 scale-75' />
                {style}
              </Button>
            ))}
            {suggestedStylesLoading && (
              <Button
                shape={ButtonShape.Pill}
                variant={ButtonVariant.Tertiary}
                icon={<SpinnerSVG className='h-5 w-5 scale-75' />}
                className='py-2'
              />
            )}
          </Footer>
        </SongDescriptionContent>
        <ResizerHandle ref={receiveResizerRef} />
      </CreateCard>
    );
  }
);

export const SimpleSongDescriptionCard = () => {
  const { setIsUploadInProgress } = useContext(UploadStateContext);
  const [songDescription, setSongDescription] = useContextSelector(
    CreateFormContext,
    (context) => context.selectState<string>([CreateModes.SIMPLE, 'prompt'])
  );

  const [instrumental, setInstrumental] = useContextSelector(
    CreateFormContext,
    (context) =>
      context.selectState<boolean>([CreateModes.SIMPLE, 'instrumental'])
  );

  const [songDescriptionInputHeight, setSongDescriptionInputHeight] =
    useContextSelector(CreateFormContext, (context) =>
      context.selectState<number>([CreateModes.SIMPLE, 'promptInputHeight'])
    );

  const setState = useContextSelector(
    CreateFormContext,
    (context) => context.setState
  );

  const onAddLyrics = useCallback(() => {
    setState((prev) => {
      const stateWithMode = setIn(prev, ['global', 'mode'], CreateModes.CUSTOM);
      const stateWithStyles = setIn(
        stateWithMode,
        [CreateModes.CUSTOM, 'styles'],
        prev[CreateModes.SIMPLE].prompt
      );
      return setIn(stateWithStyles, [CreateModes.CUSTOM, 'lyrics'], '');
    });
  }, [setState]);

  const setActiveModal = useContextSelector(
    CreateFormContext,
    (context) => context.setActiveModal
  );

  const { suggestedStyles, suggestedStylesLoading, onPickSuggestedStyle } =
    useSuggestedStyles(setSongDescription);

  const handleRecord = useCallback(() => {
    setActiveModal(CreateFormModals.AudioRecord);
    setIsUploadInProgress(true);
  }, [setActiveModal, setIsUploadInProgress]);

  const handleUploadFile = useCallback(() => {
    setActiveModal(CreateFormModals.AudioUpload);
    setIsUploadInProgress(true);
  }, [setActiveModal, setIsUploadInProgress]);

  return (
    <SongDescriptionCard
      songDescription={songDescription}
      setSongDescription={setSongDescription}
      instrumental={instrumental}
      setInstrumental={setInstrumental}
      songDescriptionInputHeight={songDescriptionInputHeight}
      setSongDescriptionInputHeight={setSongDescriptionInputHeight}
      onAddLyrics={onAddLyrics}
      onClickRecordButton={handleRecord}
      onUploadFile={handleUploadFile}
      suggestedStyles={suggestedStyles}
      suggestedStylesLoading={suggestedStylesLoading}
      onPickSuggestedStyle={onPickSuggestedStyle}
    />
  );
};

export default SongDescriptionCard;
