import { useAnimationFrame } from 'framer-motion';
import {
  Dispatch,
  SetStateAction,
  memo,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';

import {
  DraggedClip,
  DraggedObject,
  DraggedStudioTimeline,
} from '@/app/(root)/dragAndDrop/DragAndDropContext';
import Droppable, { DropOverlay } from '@/app/(root)/dragAndDrop/Droppable';
import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import { getPlaintextLyrics } from '@/components/edit2025/lyrics/getPlaintextLyrics';
import StudioContext from '@/components/studio/StudioContext';
import DEFAULT_STATE from '@/components/studio/defaultState';
import getStateAlignedLyrics from '@/components/studio/getStateAlignedLyrics';
import { useLogStudioWebUserEvent } from '@/components/studio/useLogStudioWebUserEvent';
import { Tooltip } from '@/components/tooltip/Tooltip';
import {
  useContextSelector,
  useContextSelectorRef,
} from '@/hooks/useContextSelector';
import { MusicIcon, MusicNoteIcon } from '@/icons';
import { TransactionLogger } from '@/logging/logWebUserEvent';

import CreateFormContext, {
  AddConditionType,
} from '../../v2/CreateFormContext';
import resetCreateInputs from '../../v2/actions/resetCreateInputs';
import { ConditionTypes, CreateModes } from '../../v2/types';
import { PromptInputWrapper } from '../PromptInputWrapper';
import { CreateActionShortcutsCard } from './ActionShortcutsCard';
import { CustomAdvancedOptionsCard } from './AdvancedOptionsCard';
import { Option } from './AnimatedTabs';
import { CreateCoverCard, CreateTimedConditionCard } from './ClipConditionCard';
import ClipSpeedCard from './ClipSpeedCard';
import CreateFooter from './CreateFooter';
import CreateFormDropzone from './CreateFormDropzone';
import { StudioCreateHeader } from './CreateHeader';
import { CreateExtendCard } from './ExtendCard';
import { InspirationCard } from './InspirationCard';
import { CustomLyricsCard } from './LyricsCard';
import { PersonaCard } from './PersonaCard';
import PreparingSelectionCard from './PreparingSelectionCard';
import StudioCreateContext from './StudioCreateContext';
import { CustomStylesCard } from './StylesCard';
import { CustomTitleWorkspaceCard } from './TitleWorkspaceCard';
import VoxPersonaCard from './VoxPersonaCard';
import { CardList, CardListContainer, FormContainer } from './common';

const modeOptions: Option<CreateModes>[] = [
  {
    label: 'Simple',
    // icon: <CreateIcon className='h-4 w-4' />,
    value: CreateModes.SIMPLE,
  },
  {
    label: 'Custom',
    // icon: <CreateIcon className='h-4 w-4' />,
    value: CreateModes.CUSTOM,
  },
];

export default memo(function StudioCreateForm({
  setExpanded,
  expanded,
}: {
  setExpanded?: Dispatch<SetStateAction<boolean>>;
  expanded: boolean;
}) {
  const [mode, setMode] = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.selectState<CreateModes>(['global', 'mode'])
  );
  const [modelType, setModelType] = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.selectState<string>(['global', 'model'])
  );
  const modelTypeOptions = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.modelTypeOptions
  );
  const canClear = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.canClear
  );
  const generate = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.generate
  );
  const isGenerating = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.isGenerating
  );
  const setState = useContextSelector(
    StudioCreateContext,
    ({ create }) => create.setState
  );
  const createFormStateRef = useContextSelectorRef(
    StudioCreateContext,
    ({ create }) => create.state
  );

  const onCreateClick = useCallback(
    async (transactionLogger: TransactionLogger) => {
      await generate(transactionLogger);
    },
    [generate, mode, createFormStateRef]
  );

  const onClearClick = useCallback(() => {
    setState(resetCreateInputs);
  }, [setState]);

  const getEffectiveSelection = useContextSelector(
    StudioContext,
    (ctx) => ctx.getEffectiveSelection
  );
  const getGenerateBlockingErrorMessage = useContextSelector(
    StudioContext,
    (ctx) => ctx.getGenerateBlockingErrorMessage
  );

  const [generateBlockingErrorMessage, setGenerateBlockingErrorMessage] =
    useState<string | null>(null);

  useAnimationFrame(() => {
    const selection = getEffectiveSelection();
    const errorMessage = getGenerateBlockingErrorMessage(
      selection.startSeconds,
      selection.endSeconds
    );
    if (errorMessage !== generateBlockingErrorMessage) {
      setGenerateBlockingErrorMessage(errorMessage);
    }
  });

  const projectId = useContextSelector(
    StudioContext,
    ({ projectId }) => projectId
  );

  const studioProjectId = useContextSelector(
    StudioContext,
    ({ studioProjectId }) => studioProjectId
  );

  const createBlockingErrorMessage = useContextSelector(
    CreateFormContext,
    (context) => context.createBlockingErrorMessage
  );
  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );

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

  const isStudioTimelineRendering = useContextSelector(
    CreateFormContext,
    (context) => context.isStudioTimelineRendering
  );
  const setIsStudioTimelineRendering = useContextSelector(
    CreateFormContext,
    (context) => context.setIsStudioTimelineRendering
  );
  const lastStudioTimelineRenderTimestamp = useContextSelector(
    CreateFormContext,
    (context) => context.lastStudioTimelineRenderTimestamp
  );

  const renderingDroppedStateRef = useRef<boolean>(false);
  useEffect(() => {
    renderingDroppedStateRef.current = isStudioTimelineRendering;
  }, [isStudioTimelineRendering]);

  const alignedLyricsByClipId = useContextSelector(
    StudioContext,
    (ctx) => ctx.alignedLyricsByClipId
  );

  const logStudioWebUserEvent = useLogStudioWebUserEvent();

  const handleDrop = useCallback(
    async (draggedObject: DraggedObject<'clip' | 'studio-timeline'>) => {
      if (renderingDroppedStateRef.current) {
        return;
      }

      setExpanded?.(true);

      if (draggedObject.type === 'clip') {
        addCondition(
          (draggedObject as DraggedClip).payload.clipId,
          AddConditionType.COVER
        );
      } else if (draggedObject.type === 'studio-timeline') {
        const { tracks, timing, startBeats, endBeats } = (
          draggedObject as DraggedStudioTimeline
        ).payload;

        const state = {
          ...DEFAULT_STATE,
          tracks,
          timing,
        };

        addStudioProjectStateCondition(state, ConditionTypes.COVER, {
          projectId,
          studioProjectId,
          startBeats,
          endBeats,
          title: 'Studio Selection',
          lyrics: getPlaintextLyrics(
            getStateAlignedLyrics(state, alignedLyricsByClipId, {
              startBeats,
              endBeats,
            })
          ),
        });
      }
    },
    [
      addCondition,
      addStudioProjectStateCondition,
      projectId,
      studioProjectId,
      alignedLyricsByClipId,
    ]
  );

  return (
    // outer Droppable is only shown when form is collapsed
    <Droppable
      accept={
        expanded || isStudioTimelineRendering ? [] : ['clip', 'studio-timeline']
      }
      overlay={<DropOverlay>Drop here</DropOverlay>}
      onDrop={handleDrop}
    >
      <FormContainer>
        <StudioCreateHeader
          mode={mode}
          setMode={setMode}
          modeOptions={modeOptions}
          modelType={modelType}
          setModelType={setModelType}
          modelTypeOptions={modelTypeOptions}
          expanded={expanded}
          setExpanded={setExpanded}
        />
        {expanded ? (
          <>
            <CardListContainer className='card-popout-boundary'>
              {mode === CreateModes.ADJUST_SPEED && (
                <CardList active>
                  <CreateFormDropzone
                    accept={['clip', 'studio-timeline']}
                    onDrop={handleDrop as any}
                  />
                  <ClipSpeedCard />
                  <CustomTitleWorkspaceCard />
                </CardList>
              )}

              {mode === CreateModes.SIMPLE && (
                <CardList active>
                  <CreateFormDropzone
                    accept={['clip', 'studio-timeline']}
                    onDrop={handleDrop as any}
                  />
                  <PromptInputWrapper />
                </CardList>
              )}

              {mode === CreateModes.CUSTOM && (
                <CardList active>
                  {isStudioTimelineRendering && (
                    <PreparingSelectionCard
                      dropTimestamp={lastStudioTimelineRenderTimestamp}
                      onCancel={() => setIsStudioTimelineRendering(false)}
                    />
                  )}
                  <CreateActionShortcutsCard />
                  <CreateCoverCard />
                  <CreateTimedConditionCard />
                  <CreateExtendCard />
                  <InspirationCard />
                  <PersonaCard />
                  <CreateFormDropzone
                    accept={['clip', 'studio-timeline']}
                    onDrop={handleDrop as any}
                  />
                  <CustomLyricsCard />
                  <CustomStylesCard />
                  <CustomAdvancedOptionsCard />
                  <CustomTitleWorkspaceCard />
                  <VoxPersonaCard />
                </CardList>
              )}
            </CardListContainer>
            <CreateFooter
              canClear={canClear}
              isGenerating={isGenerating}
              onCreateClick={(transactionLogger: TransactionLogger) => {
                logStudioWebUserEvent(
                  {
                    actionName: 'StudioCreateFormGenerateClicked',
                    context: {},
                  },
                  transactionLogger
                );
                onCreateClick(transactionLogger);
              }}
              onClearClick={onClearClick}
              generateBlockingErrorMessage={createBlockingErrorMessage}
              buttonText={'Create'}
            />
          </>
        ) : (
          setExpanded && (
            <div className='flex max-w-[48px] flex-col justify-center gap-4 px-1 py-4'>
              <Tooltip placement='right' label='Simple'>
                <Button
                  onClick={() => {
                    setExpanded(true);
                    setMode(CreateModes.SIMPLE);
                  }}
                  icon={<MusicNoteIcon className='h-5 w-5' />}
                  variant={ButtonVariant.Tertiary}
                  shape={ButtonShape.Pill}
                />
              </Tooltip>
              <Tooltip placement='right' label='Custom'>
                <Button
                  onClick={() => {
                    setExpanded(true);
                    setMode(CreateModes.CUSTOM);
                  }}
                  icon={<MusicIcon className='h-5 w-5' />}
                  variant={ButtonVariant.Tertiary}
                  shape={ButtonShape.Pill}
                />
              </Tooltip>
            </div>
          )
        )}
      </FormContainer>
    </Droppable>
  );
});
