import { runInAction } from 'mobx';
import { memo, useCallback, useEffect } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { ChatClient } from '@/app/(root)/chat/ChatClient';
import { OrpheusAblyProvider } from '@/app/(root)/chat/OrpheusAblyProvider';
import { useOrpheusExperimentGroup } from '@/app/(root)/chat/hooks/useOrpheusExperimentGroup';
import {
  DraggedObject,
  DraggedObjectType,
} from '@/app/(root)/dragAndDrop/DragAndDropContext';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { ModalTypes } from '@/components/modal/constants/ModalTypes';
import { toast } from '@/components/toast/Toast';
import { useBreakpointMd } from '@/hooks/useBreakpoint';
import { useContextSelector } from '@/hooks/useContextSelector';
import { useHasUnexpiredPrompt } from '@/hooks/useHasUnexpiredPrompt';
import {
  TransactionLogger,
  createTransactionLogger,
} from '@/logging/logWebUserEvent';
import { FeatureKey } from '@/state/sessionStore';
import { CROW_WEB_UI, MAX_TITLE_CHARS } from '@/utils/constants';
import { isDevOrStaging } from '@/utils/environment';
import { isSubscriber } from '@/utils/session';
import {
  DEFAULT_CROW_MODEL_NAME,
  canUseModel,
  getFirstNSongsFromPlaylist,
} from '@/utils/utils';

import CreateFormContext, {
  AddConditionType,
} from '../../v2/CreateFormContext';
import resetCreateInputs from '../../v2/actions/resetCreateInputs';
import { ConditionTypes, CreateModes } from '../../v2/types';
import { CreateAudioUpload } from '../AudioSectionNew';
import { CreateActionShortcutsCard } from './ActionShortcutsCard';
import { CustomAdvancedOptionsCard } from './AdvancedOptionsCard';
import { Option } from './AnimatedTabs';
import ChameleonModeCard from './ChameleonModeCard';
import { CreateCoverCard, CreateTimedConditionCard } from './ClipConditionCard';
import ClipSpeedCard from './ClipSpeedCard';
import CreateFooter from './CreateFooter';
import CreateFormDropzone from './CreateFormDropzone';
import CreateHeader from './CreateHeader';
import CreateInspirationDropzone from './CreateInspirationDropzone';
import CreateSampleDropzone from './CreateSampleDropzone';
import { CreateExtendCard } from './ExtendCard';
import { InspirationCard } from './InspirationCard';
import { CustomLyricsCard } from './LyricsCard';
import { PersonaCard } from './PersonaCard';
import CreateReuseStylesLyricsCard from './ReuseStylesLyricsCard';
import { SampleCard } from './SampleCard';
import { SimpleSongDescriptionCard } from './SongDescriptionCard';
import { CustomStylesCard } from './StylesCard';
import { CustomTitleWorkspaceCard } from './TitleWorkspaceCard';
import VoxPersonaCard from './VoxPersonaCard';
import { CardList, CardListContainer, FormContainer } from './common';
import useRemixIntentConsumer from './useRemixIntentConsumer';

const createModeOptions: Option<CreateModes>[] = [
  { label: 'Simple', value: CreateModes.SIMPLE },
  { label: 'Custom', value: CreateModes.CUSTOM },
];

const createModeOptionsForChat: Option<CreateModes>[] = [
  { label: 'Chat', value: CreateModes.CHAT },
  { label: 'Custom', value: CreateModes.CUSTOM },
];

function CreateForm({
  onMobileCreate,
}: {
  onMobileCreate?: () => void;
  showModeSwitcher?: boolean;
}) {
  const [mode, setMode] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<CreateModes>(['global', 'mode'])
  );
  const [modelType, setModelType] = useContextSelector(
    CreateFormContext,
    (context) => context.selectState<string>(['global', 'model'])
  );
  const modelTypeOptions = useContextSelector(
    CreateFormContext,
    (context) => context.modelTypeOptions
  );
  const creditsRemaining = useContextSelector(
    CreateFormContext,
    (context) => context.creditsRemaining
  );
  const setActiveModal = useContextSelector(
    CreateFormContext,
    (context) => context.setActiveModal
  );
  const activeModal = useContextSelector(
    CreateFormContext,
    (context) => context.activeModal
  );
  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );
  const addInspirationClips = useContextSelector(
    CreateFormContext,
    (context) => context.addInspirationClips
  );
  const addSampleClips = useContextSelector(
    CreateFormContext,
    (context) => context.addSampleClips
  );
  const state = useContextSelector(
    CreateFormContext,
    (context) => context.state
  );

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

  const currentTitle = useContextSelector(CreateFormContext, (context) =>
    mode === CreateModes.CUSTOM
      ? context.selectState<string>([CreateModes.CUSTOM, 'title'])[0]
      : ''
  );

  const { session, menus, clips, genForm } = useStores();

  const headerProps = {
    mode,
    setMode,
    modelType,
    setModelType,
    modelTypeOptions,
    creditsRemaining,
    setActiveModal,
    activeModal,
    onOutOfCreditsClick: () => {
      menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
      menus.openModal(ModalTypes.UPSELL_MODAL);
    },
  };

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

  const generate = useContextSelector(
    CreateFormContext,
    (context) => context.generate
  );
  const onCreateClick = useCallback(
    (transactionLogger: TransactionLogger) => {
      if (!isSubscriber(session) && session.credits <= 0) {
        toast({
          title: 'Out of Credits',
          description: 'Upgrade to Pro.',
          status: 'warning',
          duration: 4000,
          isClosable: true,
        });

        menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
        menus.openModal(ModalTypes.UPSELL_MODAL);
        return;
      }

      if (currentTitle && currentTitle.length > MAX_TITLE_CHARS) {
        toast({
          title: 'Title Too Long',
          description: `Title exceeds maximum length of ${MAX_TITLE_CHARS} characters.`,
          status: 'error',
          duration: 4000,
          isClosable: true,
        });
        return;
      }

      // Log create step for onboarding
      session.logCreateOnboardingStepMounted('create_tooltip');

      generate(transactionLogger);
    },
    [generate, session, menus, currentTitle]
  );

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

  const footerProps = {
    canClear,
    generateBlockingErrorMessage: createBlockingErrorMessage,
    onCreateClick,
    onClearClick,
    isGenerating,
    isOutOfCredits: !isSubscriber(session) && session.credits <= 0,
    onMobileCreate,
  };

  const handleDropClip = useCallback(
    (
      draggedObject: DraggedObject<DraggedObjectType>,
      _event: React.MouseEvent<HTMLDivElement>
    ) => {
      if (draggedObject.type === 'clip' && 'clipId' in draggedObject.payload) {
        addCondition(draggedObject.payload.clipId, AddConditionType.COVER);
      }
    },
    [addCondition]
  );

  const handleDropInspiration = useCallback(
    (
      draggedObject: DraggedObject<DraggedObjectType>,
      _event: React.MouseEvent<HTMLDivElement>
    ) => {
      if (draggedObject.type === 'clip' && 'clipId' in draggedObject.payload) {
        addInspirationClips([draggedObject.payload.clipId]);
      }
    },
    [addInspirationClips]
  );

  const handleDropSample = useCallback(
    (
      draggedObject: DraggedObject<DraggedObjectType>,
      _event: React.MouseEvent<HTMLDivElement>
    ) => {
      if (draggedObject.type === 'clip' && 'clipId' in draggedObject.payload) {
        addSampleClips([draggedObject.payload.clipId]);
      }
    },
    [addSampleClips]
  );

  // Determine visibility logic
  const hasRemixCondition = !!(
    state.global.untimedConditions.cover || state.global.timedCondition
  );

  // Check for inspiration from both individual clips and playlist conditions
  const playlistCondition =
    state.global.untimedConditions[ConditionTypes.PLAYLIST];
  const playlist = playlistCondition
    ? clips.playlistById[playlistCondition.playlistId]
    : null;
  const playlistClipCount = playlist
    ? Math.min(getFirstNSongsFromPlaylist(playlist, 4).length, 4)
    : 0;
  const individualClipCount =
    state.global.untimedConditions[ConditionTypes.INSPIRATION]?.clipIds
      ?.length || 0;

  const hasInspirationCondition = !!(individualClipCount || playlistClipCount);

  // Check for sample clips
  const sampleClipCount =
    state.global.untimedConditions[ConditionTypes.SAMPLE]?.clipIds?.length || 0;
  const hasSampleCondition = !!sampleClipCount;

  const showBothDropzones =
    !hasRemixCondition && !hasInspirationCondition && !hasSampleCondition;

  // Calculate total inspiration song count for the dropzone (from both sources)
  const inspirationCount = Math.min(individualClipCount + playlistClipCount, 4);
  const sampleCount = Math.min(sampleClipCount, 10);
  const { isControlGroup: isChatExpControlGroup } = useOrpheusExperimentGroup();
  const isChatExpEnabled = !isChatExpControlGroup;
  const isMobile = !useBreakpointMd();

  useRemixIntentConsumer();

  // Keyboard shortcut for Command + Enter to trigger create
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
        if (mode !== CreateModes.CHAT && !isGenerating) {
          event.preventDefault();
          const transactionLogger = createTransactionLogger();
          onCreateClick(transactionLogger);
        }
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [mode, isGenerating, onCreateClick]);

  useEffect(() => {
    if (
      canUseModel(session.billingModels, DEFAULT_CROW_MODEL_NAME) &&
      !genForm.hasSeenCrow &&
      session.checkGate(CROW_WEB_UI)
    ) {
      setModelType(DEFAULT_CROW_MODEL_NAME);
      runInAction(() => {
        genForm.hasSeenCrow = true;
      });
    }
  }, [session.billingModels]);

  const { hasUnexpiredPrompt } = useHasUnexpiredPrompt();

  // Auto-switch to chat mode if there's an unexpired prompt
  useEffect(() => {
    if (hasUnexpiredPrompt && isChatExpEnabled && mode !== CreateModes.CHAT) {
      setMode(CreateModes.CHAT);
    }
  }, [hasUnexpiredPrompt, isChatExpEnabled, mode, setMode]);

  return (
    <FormContainer>
      {isMobile || !isChatExpEnabled ? (
        <CreateHeader
          {...headerProps}
          modeOptions={
            isChatExpEnabled && isMobile
              ? createModeOptionsForChat
              : createModeOptions
          }
        />
      ) : null}
      {headerProps.mode === CreateModes.CHAT && isMobile ? (
        <OrpheusAblyProvider>
          <div className='h-full w-full'>
            <ChatClient model={modelType} offsetHeight={182} />
          </div>
        </OrpheusAblyProvider>
      ) : (
        <CardListContainer className='card-popout-boundary'>
          <CardList active={headerProps.mode === CreateModes.ADJUST_SPEED}>
            {(showBothDropzones || hasRemixCondition) && (
              <CreateFormDropzone accept={['clip']} onDrop={handleDropClip} />
            )}
            {(showBothDropzones || hasInspirationCondition) && (
              <CreateInspirationDropzone
                accept={['clip']}
                onDrop={handleDropInspiration}
                currentCount={inspirationCount}
                maxCount={4}
              />
            )}
            {isDevOrStaging && (showBothDropzones || hasSampleCondition) && (
              <CreateSampleDropzone
                accept={['clip']}
                onDrop={handleDropSample}
                currentCount={sampleCount}
                maxCount={10}
              />
            )}
            <ClipSpeedCard />
            <CustomTitleWorkspaceCard />
          </CardList>
          <CardList active={headerProps.mode === CreateModes.CUSTOM}>
            <CreateActionShortcutsCard />
            <CreateAudioUpload />
            <CreateCoverCard />
            <CreateTimedConditionCard />
            <CreateReuseStylesLyricsCard />
            <CreateExtendCard />
            <InspirationCard />
            {isDevOrStaging && <SampleCard />}
            <PersonaCard />
            {(showBothDropzones || hasRemixCondition) && (
              <CreateFormDropzone accept={['clip']} onDrop={handleDropClip} />
            )}
            {(showBothDropzones || hasInspirationCondition) && (
              <CreateInspirationDropzone
                accept={['clip']}
                onDrop={handleDropInspiration}
                currentCount={inspirationCount}
                maxCount={4}
              />
            )}
            {isDevOrStaging && (showBothDropzones || hasSampleCondition) && (
              <CreateSampleDropzone
                accept={['clip']}
                onDrop={handleDropSample}
                currentCount={sampleCount}
                maxCount={10}
              />
            )}
            <CustomLyricsCard />
            <CustomStylesCard />
            <CustomAdvancedOptionsCard />
            <CustomTitleWorkspaceCard />
            <ChameleonModeCard />
            <VoxPersonaCard />
          </CardList>
          <CardList active={headerProps.mode === CreateModes.SIMPLE}>
            <CreateAudioUpload />
            <CreateCoverCard />
            <CreateTimedConditionCard />
            <CreateExtendCard />
            <InspirationCard />
            {isDevOrStaging && <SampleCard />}
            <PersonaCard />
            {(showBothDropzones || hasRemixCondition) && (
              <CreateFormDropzone accept={['clip']} onDrop={handleDropClip} />
            )}
            {(showBothDropzones || hasInspirationCondition) && (
              <CreateInspirationDropzone
                accept={['clip']}
                onDrop={handleDropInspiration}
                currentCount={inspirationCount}
                maxCount={4}
              />
            )}
            {isDevOrStaging && (showBothDropzones || hasSampleCondition) && (
              <CreateSampleDropzone
                accept={['clip']}
                onDrop={handleDropSample}
                currentCount={sampleCount}
                maxCount={10}
              />
            )}
            <SimpleSongDescriptionCard />
          </CardList>
        </CardListContainer>
      )}
      {!isSubscriber(session) && session.credits <= 0 && (
        <div className='mx-4 mb-4 rounded-xl border border-accent-error/20 bg-accent-error/10 p-4 shadow-sm'>
          <div className='flex items-center gap-3'>
            <div className='flex h-5 w-5 items-center justify-center rounded-full bg-accent-error'>
              <span className='text-xs font-bold text-white'>!</span>
            </div>
            <div className='flex-1'>
              <div className='font-medium text-accent-error-on-primary'>
                Out of Credits
              </div>
              <div className='text-sm text-foreground-secondary'>
                You&apos;ve used all your credits. Upgrade to Pro.
              </div>
            </div>
            <Button
              variant={ButtonVariant.Primary}
              shape={ButtonShape.Pill}
              size={ButtonSize.Small}
              className='bg-accent-error text-white hover:bg-accent-error/90'
              aria-label='Upgrade to Pro to get more credits'
              onClick={() => {
                menus.setCurrentUpsellFeature(FeatureKey.REMASTER);
                menus.openModal(ModalTypes.UPSELL_MODAL);
              }}
            >
              Upgrade Now
            </Button>
          </div>
        </div>
      )}
      {headerProps.mode !== CreateModes.CHAT ? (
        <CreateFooter {...footerProps} />
      ) : null}
    </FormContainer>
  );
}

export default memo(CreateForm);
