import styled from '@emotion/styled';
import { useStatsigClient } from '@statsig/react-bindings';
import { getSecondsFromZero } from '@suno/studiokit/timeMapping';
import { noop } from 'lodash-es';
import { useEffect, useMemo, useState } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import AdvancedOptionsCard from '@/app/(root)/create/createV2/componentsQ3/AdvancedOptionsCard';
import AnimatedTabs from '@/app/(root)/create/createV2/componentsQ3/AnimatedTabs';
import LyricsCard from '@/app/(root)/create/createV2/componentsQ3/LyricsCard';
import StylesCard from '@/app/(root)/create/createV2/componentsQ3/StylesCard';
import { bigSpace } from '@/app/(root)/create/createV2/componentsQ3/themes';
import CreateFormContext from '@/app/(root)/create/v2/CreateFormContext';
import {
  ConditionTypes,
  LyricsInputModes,
  VocalGenders,
} from '@/app/(root)/create/v2/types';
import { getPlaintextLyrics } from '@/components/edit2025/lyrics/getPlaintextLyrics';
import SpinnerSVG from '@/components/svg/SpinnerSVG';
import { Tooltip } from '@/components/tooltip/Tooltip';
import getClipGeneratePayload from '@/hooks/getClipGeneratePayload';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  ArrowUpIcon,
  CloseIcon,
  CollapseContentIcon,
  CreateIcon,
  ExpandContentIcon,
  LibraryIcon,
  LyricsIcon,
  MusicIcon,
  RemixIcon,
  TextCreateIcon,
  UploadIcon,
} from '@/icons';
import { createTransactionLogger } from '@/logging/logWebUserEvent';
import { MAX_CUSTOM_PROMPT_CHARS_LONGEST } from '@/utils/constants';

import Button, { ButtonShape, ButtonVariant } from '../../button/Button';
import StudioContext from '../StudioContext';
import UploadButtonRenderer from '../UploadButtonRenderer';
import promoteTakeLane from '../actions/promoteTakeLane';
import DEFAULT_STATE from '../defaultState';
import getSelectedClips from '../getClipsInRange';
import getStateAlignedLyrics from '../getStateAlignedLyrics';
import { getTrimmedUnmutedTracks } from '../helpers/getTrimmedUnmutedTracks';
import {
  getDerivedTiming,
  getFocusedStudioClip,
  getFocusedTrack,
  getSelectedTracks,
  getSelectionEndBeats,
  getSelectionStartBeats,
  getTakeLanesById,
} from '../selectors';
import { AFTER_LAST_TRACK, StudioProjectState } from '../types';
import useContextualBar from '../useContextualBar';
import { useLogStudioWebUserEvent } from '../useLogStudioWebUserEvent';
import { StudioLayoutManagerContext } from '../useStudioLayoutManager';
import ContextualBarInstrumentPicker from './ContextualBarInstrumentPicker';
import ContextualBarSplitButton from './ContextualBarSplitButton';
import ExpandingInput from './ExpandingInput';
import { MainButton, Positioner, Wrapper } from './components';

const Header = styled.div`
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-grow: 1;
  width: 100%;
  padding: 8px 8px 0 8px;
  gap: 16px;
`;

const ExpandedContentWrapper = styled.div`
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 8px;
  > * {
    min-width: 350px;
  }
  gap: ${bigSpace}px;
  position: relative;
  min-height: 244px;
  height: auto;
`;

export type ContextualBarInputScheme =
  | 'style'
  | 'lyrics-style'
  | 'control-style';

const advancedOrLyrics = [
  { value: 'lyrics', label: 'Lyrics' },
  { value: 'advanced', label: 'Advanced Options' },
];

export default function ContextualBar() {
  const statsigClient = useStatsigClient();
  const {
    mode,
    hasClipsInSelection,
    formState,
    handleSubmit,
    isGenerating,
    disabledReason,
    canCover,
    canRecreate,
    setEnableCover,
    setEnableRecreate,
  } = useContextualBar();

  // Determine the current mode for the split button menu
  const currentMenuMode = useMemo<'create' | 'cover' | 'recreate'>(() => {
    if (mode === 'recreate') return 'recreate';
    if (mode === 'cover') return 'cover';
    return 'create';
  }, [mode]);

  const inputScheme = useMemo<ContextualBarInputScheme>(() => {
    if (formState.instrument.type === 'song') {
      return 'lyrics-style';
    } else if (formState.instrument.type === 'custom') {
      return 'control-style';
    } else if (formState.instrument.type === 'vocalPreset') {
      return 'lyrics-style';
    } else if (formState.instrument.type === 'nonVocalPreset') {
      return 'style';
    }
    throw new Error(
      `invalid instrument ${JSON.stringify(formState.instrument)}`
    );
  }, [formState.instrument]);

  const hasLyricsInput = inputScheme === 'lyrics-style';
  const hasControlTagsInput = inputScheme === 'control-style';

  const setExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (context) => context?.setContextualBarExpanded || noop
  );

  const expanded = useContextSelector(
    StudioLayoutManagerContext,
    (context) => context?.contextualBarExpanded || false
  );

  const disableLyrics = ['custom', 'nonVocalPreset'].includes(
    formState.instrument.type
  );

  const submitText = useMemo(() => {
    return mode === 'recreate'
      ? 'Recreate'
      : mode === 'cover'
        ? 'Cover'
        : hasClipsInSelection
          ? 'Replace'
          : 'Create';
  }, [mode, hasClipsInSelection]);

  const hasClipsOnMultipleTracksSelected = useContextSelector(
    StudioContext,
    (ctx) => {
      const selectedTracks = getSelectedTracks(ctx.state);
      const selectedTrackClips = selectedTracks
        .map((t) =>
          getSelectedClips(
            getSelectionStartBeats(ctx.state),
            getSelectionEndBeats(ctx.state),
            t.clips
          )
        )
        .filter((list) => list.length > 0);
      return selectedTrackClips.length > 1;
    }
  );

  const hasTakeLaneSelected = useContextSelector(StudioContext, (ctx) => {
    const takeLanesById = getTakeLanesById(ctx.state);
    return !!ctx.state.selection.trackIds.find((id) => takeLanesById[id]);
  });

  const hasClipOnTakeLaneSelected = useContextSelector(
    StudioContext,
    (ctx) =>
      ctx.state.selection.trackIds.length === 1 &&
      getSelectedClips(
        getSelectionStartBeats(ctx.state),
        getSelectionEndBeats(ctx.state),
        getTakeLanesById(ctx.state)[ctx.state.selection.trackIds[0]]?.clips ||
          []
      ).length > 0
  );

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

  const projectId = useContextSelector(StudioContext, (ctx) => ctx.projectId);
  const studioProjectId = useContextSelector(
    StudioContext,
    (ctx) => ctx.studioProjectId
  );
  const alignedLyricsByClipId = useContextSelector(
    StudioContext,
    (ctx) => ctx.alignedLyricsByClipId
  );
  const hasFocusedTrack = useContextSelector(StudioContext, (ctx) => {
    return (
      !!getFocusedTrack(ctx.state) ||
      ctx.state.selection.focusedTrackId === AFTER_LAST_TRACK
    );
  });

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

  const stateRef = useContextSelector(StudioContext, (ctx) => ctx.stateRef);
  const canTogglePanels = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx?.layoutMode === 'horizontal'
  );
  const createPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx?.createPanelExpanded
  );
  const libraryPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx?.libraryPanelExpanded
  );
  const setCreatePanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx?.setCreatePanelExpanded
  );
  const setLibraryPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx?.setLibraryPanelExpanded
  );

  const { session } = useStores();

  const [widthClass, setWidthClass] = useState('');
  const finalExpanded = widthClass ? false : expanded;
  const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
  useEffect(() => {
    if (disableLyrics) {
      setShowAdvancedOptions(false);
    }
  }, [disableLyrics]);

  // Compute current selection duration in seconds for hover pricing hints
  const selectionStartBeats = getSelectionStartBeats(stateRef.current);
  const selectionEndBeats = getSelectionEndBeats(stateRef.current);
  const timing = getDerivedTiming(stateRef.current);
  const selectionDurationSeconds = Math.max(
    0,
    getSecondsFromZero(selectionEndBeats, timing) -
      getSecondsFromZero(selectionStartBeats, timing)
  );
  const isShortReplace = mode === 'replace' && selectionDurationSeconds < 30;
  const isShortStem = mode === 'create' && selectionDurationSeconds < 30;
  const isShortRecreate = useContextSelector(StudioContext, (ctx) => {
    const focusedStudioClip = getFocusedStudioClip(ctx.state);
    if (!focusedStudioClip) return false;
    const focusedClip = focusedStudioClip?.clipId
      ? ctx.clipsById[focusedStudioClip.clipId]
      : null;
    if (!focusedClip || focusedClip.user_id !== session.user.id) return false;
    const generatePayload = getClipGeneratePayload(focusedClip);

    if (
      !generatePayload.references ||
      generatePayload.references.length === 0
    ) {
      return false;
    }

    const reference = generatePayload.references[0];

    if (reference.type === 'Infill' || reference.type === 'FixedInfill') {
      return (
        reference.durationSeconds !== undefined &&
        reference.durationSeconds < 30
      );
    } else if (
      reference.type === 'StemCondition' ||
      reference.type === 'GenStem'
    ) {
      const duration = focusedClip.metadata.duration;
      return typeof duration === 'number' && duration < 30;
    }

    return false;
  });
  const showShortHover = isShortReplace || isShortStem || isShortRecreate;
  const shortClipPricingEnabled =
    !!statsigClient?.checkGate('short-clip-pricing');

  const logStudioWebUserEvent = useLogStudioWebUserEvent();
  const contextualGenerateButtonHoveredRef = useContextSelector(
    StudioContext,
    (ctx) => ctx.timelineController.contextualGenerateButtonHoveredRef
  );

  if (hasTakeLaneSelected) {
    return (
      <Positioner
        setWidthClass={setWidthClass}
        key='take-lane-contextual-bar-positioner'
      >
        <Wrapper vertical={false}>
          <Tooltip
            label={
              !hasClipOnTakeLaneSelected
                ? 'Select all or part of a clip on the take lane'
                : ''
            }
          >
            <Button
              shape={ButtonShape.Pill}
              icon={<ArrowUpIcon className='h-4 w-4' />}
              disabled={!hasClipOnTakeLaneSelected}
              onClick={() => {
                const takeLane = getTakeLanesById(stateRef.current)[
                  stateRef.current.selection.trackIds[0]
                ];
                const selectionStartBeats = getSelectionStartBeats(
                  stateRef.current
                );
                const selectionEndBeats = getSelectionEndBeats(
                  stateRef.current
                );
                if (takeLane) {
                  setState(
                    promoteTakeLane(
                      takeLane.id,
                      selectionStartBeats,
                      selectionEndBeats
                    )(stateRef.current)
                  );
                }
              }}
            >
              Copy to Main Track
            </Button>
          </Tooltip>
        </Wrapper>
      </Positioner>
    );
  }

  if (!hasFocusedTrack) {
    return (
      <Positioner
        setWidthClass={setWidthClass}
        key='no-focused-track-contextual-bar-positioner'
      >
        <Wrapper vertical={false}>
          {canTogglePanels && !!setCreatePanelExpanded && (
            <Tooltip label='Press 1 to open or close the Create panel'>
              <Button
                shape={ButtonShape.Pill}
                icon={
                  createPanelExpanded ? (
                    <CloseIcon className='h-4 w-4' />
                  ) : (
                    <CreateIcon className='h-4 w-4' />
                  )
                }
                onClick={() => {
                  setCreatePanelExpanded((prev) => !prev);
                }}
              >
                Create Song
              </Button>
            </Tooltip>
          )}
          {canTogglePanels && !!setLibraryPanelExpanded && (
            <Tooltip label='Press 2 to open or close the Library panel'>
              <Button
                shape={ButtonShape.Pill}
                icon={
                  libraryPanelExpanded ? (
                    <CloseIcon className='h-4 w-4' />
                  ) : (
                    <LibraryIcon className='h-4 w-4' />
                  )
                }
                onClick={() => {
                  setLibraryPanelExpanded((prev) => !prev);
                }}
              >
                Open Library
              </Button>
            </Tooltip>
          )}
          <UploadButtonRenderer
            renderButton={(handleUpload) => (
              <Button
                shape={ButtonShape.Pill}
                icon={<UploadIcon className='h-4 w-4' />}
                onClick={handleUpload}
              >
                Upload Audio
              </Button>
            )}
          />
        </Wrapper>
      </Positioner>
    );
  }

  if (hasClipsOnMultipleTracksSelected) {
    return (
      <Positioner
        setWidthClass={setWidthClass}
        key='contextual-bar-positioner'
        withGlowEffect
      >
        <Wrapper vertical={false}>
          <Button
            shape={ButtonShape.Pill}
            icon={<RemixIcon className='h-4 w-4' />}
            onClick={() => {
              const tracks = getTrimmedUnmutedTracks(stateRef.current);
              const timing = getDerivedTiming(stateRef.current);
              const selectionStartBeats = getSelectionStartBeats(
                stateRef.current
              );
              const selectionEndBeats = getSelectionEndBeats(stateRef.current);
              const state: StudioProjectState = {
                ...DEFAULT_STATE,
                tracks,
                timing: {
                  type: 'manual',
                  ...timing,
                },
              };
              setCreatePanelExpanded?.(true);
              addStudioProjectStateCondition(state, ConditionTypes.COVER, {
                projectId: projectId,
                studioProjectId: studioProjectId,
                startBeats: selectionStartBeats,
                endBeats: selectionEndBeats,
                lyrics: getPlaintextLyrics(
                  getStateAlignedLyrics(state, alignedLyricsByClipId, {
                    startBeats: selectionStartBeats,
                    endBeats: selectionEndBeats,
                  })
                ),
              });
            }}
          >
            Remix Selection
          </Button>
        </Wrapper>
      </Positioner>
    );
  }

  return (
    <Positioner
      setWidthClass={setWidthClass}
      key='contextual-bar-positioner'
      withGlowEffect
    >
      <Wrapper vertical={finalExpanded}>
        {finalExpanded ? (
          <>
            <Header>
              <Button
                shape={ButtonShape.Pill}
                variant={ButtonVariant.Standard}
                icon={CollapseContentIcon}
                onClick={() => setExpanded(false)}
              />
              <ContextualBarInstrumentPicker
                instrument={formState.instrument}
                setInstrument={formState.setInstrument}
              />
              <div className='flex-grow' />
              {/* <ContextualBarReplaceModePicker
                replaceMode={formState.replaceMode}
                setReplaceMode={formState.setReplaceMode}
              /> */}
              {!disableLyrics && (
                <AnimatedTabs
                  options={advancedOrLyrics}
                  value={showAdvancedOptions ? 'advanced' : 'lyrics'}
                  onChange={(option) => {
                    setShowAdvancedOptions(option.value === 'advanced');
                  }}
                />
              )}
              <Tooltip
                label={
                  disabledReason ||
                  (shortClipPricingEnabled
                    ? showShortHover
                      ? '4 Credits'
                      : '10 Credits'
                    : '10 Credits')
                }
              >
                {canCover || canRecreate ? (
                  <ContextualBarSplitButton
                    onMouseEnter={() => {
                      contextualGenerateButtonHoveredRef.current = true;
                    }}
                    onMouseLeave={() => {
                      contextualGenerateButtonHoveredRef.current = false;
                    }}
                    submitText={submitText}
                    isGenerating={isGenerating}
                    disabledReason={disabledReason ?? undefined}
                    currentMenuMode={currentMenuMode}
                    onSubmit={() => {
                      const transactionLogger = createTransactionLogger();
                      logStudioWebUserEvent(
                        {
                          actionName: 'StudioContextualGenerateClicked',
                          context: {
                            contextualGenerateMode: mode,
                          },
                        },
                        transactionLogger
                      );
                      handleSubmit(transactionLogger);
                    }}
                    onSelectMode={(selectedMode) => {
                      setEnableCover(selectedMode === 'cover');
                      setEnableRecreate(selectedMode === 'recreate');
                    }}
                    menuPlacement='bottom-right'
                    SpinnerComponent={SpinnerSVG}
                    showRecreate={canRecreate}
                    showCover={canCover}
                  />
                ) : (
                  <MainButton
                    onMouseEnter={() => {
                      contextualGenerateButtonHoveredRef.current = true;
                    }}
                    onMouseLeave={() => {
                      contextualGenerateButtonHoveredRef.current = false;
                    }}
                    variant={ButtonVariant.Aura}
                    shape={ButtonShape.Pill}
                    disabled={isGenerating || !!disabledReason}
                    icon={isGenerating ? <SpinnerSVG /> : <CreateIcon />}
                    onClick={() => {
                      const transactionLogger = createTransactionLogger();
                      logStudioWebUserEvent(
                        {
                          actionName: 'StudioContextualGenerateClicked',
                          context: {
                            contextualGenerateMode: mode,
                          },
                        },
                        transactionLogger
                      );
                      handleSubmit(transactionLogger);
                    }}
                  >
                    {submitText}
                  </MainButton>
                )}
              </Tooltip>
            </Header>
            <ExpandedContentWrapper>
              <StylesCard
                nested
                fixed
                styles={formState.styles}
                setStyles={formState.setStyles}
                expanded={true}
                setExpanded={noop}
                suggestedStyles={[]}
                onPickSuggestedStyle={noop}
                hasSavedPrompts={false}
                onUndoSetStyles={noop}
                canUndoSetStyles={false}
                onUpsampleStyles={noop}
                canUpsampleStyles={false}
                isUpsamplingStyles={false}
                canSavePrompt={false}
                onSavePrompt={noop}
                setActiveModal={noop}
                stylesInputHeight={170}
                model='crow'
              />
              {!disableLyrics && !showAdvancedOptions && (
                <LyricsCard
                  nested
                  fixed
                  lyrics={formState.lyrics}
                  setLyrics={formState.setLyrics}
                  expanded={true}
                  setExpanded={noop}
                  onSavePrompt={noop}
                  canSavePrompt={false}
                  lyricsInputHeight={170}
                />
              )}
              {(disableLyrics || showAdvancedOptions) && (
                <AdvancedOptionsCard
                  nested
                  fixed
                  expanded={true}
                  setExpanded={noop}
                  // hide irrelevant inputs
                  lyricsMode={LyricsInputModes.MANUAL}
                  setLyricsMode={noop}
                  showLyricsMode={false}
                  vocalGender={VocalGenders.UNSPECIFIED}
                  setVocalGender={noop}
                  showVocalGender={false}
                  model='crow'
                  excludeStyles={formState.excludeStyles}
                  setExcludeStyles={formState.setExcludeStyles}
                  weirdness={formState.weirdness}
                  setWeirdness={formState.setWeirdness}
                  showWeirdness
                  styleInfluence={formState.styleInfluence}
                  setStyleInfluence={formState.setStyleInfluence}
                  showStyleInfluence
                  audioInfluence={formState.audioInfluence}
                  setAudioInfluence={formState.setAudioInfluence}
                  showAudioInfluence
                />
              )}
            </ExpandedContentWrapper>
          </>
        ) : (
          <>
            <Button
              className='hide-sub-lg'
              shape={ButtonShape.Pill}
              variant={ButtonVariant.Standard}
              icon={ExpandContentIcon}
              onClick={() => setExpanded(true)}
            />
            <ContextualBarInstrumentPicker
              instrument={formState.instrument}
              setInstrument={formState.setInstrument}
            />
            {hasControlTagsInput && (
              <ExpandingInput
                textareaRows={4}
                icon={<TextCreateIcon className='text-foreground-inactive' />}
                value={formState.controlTags}
                setValue={formState.setControlTags}
                placeholder='Instrument'
                charLimit={80}
              />
            )}
            <Tooltip label='Styles' placement='top'>
              <ExpandingInput
                doubleWidth={!hasLyricsInput && !hasControlTagsInput}
                icon={<MusicIcon className='text-foreground-inactive' />}
                value={formState.styles}
                setValue={formState.setStyles}
                placeholder='Styles'
                textareaRows={4}
                charLimit={MAX_CUSTOM_PROMPT_CHARS_LONGEST}
              />
            </Tooltip>
            {hasLyricsInput && (
              <ExpandingInput
                textareaRows={12}
                icon={<LyricsIcon className='text-foreground-inactive' />}
                value={formState.lyrics}
                setValue={formState.setLyrics}
                placeholder='Lyrics'
                charLimit={MAX_CUSTOM_PROMPT_CHARS_LONGEST}
              />
            )}
            <Tooltip
              label={
                disabledReason ||
                (shortClipPricingEnabled
                  ? showShortHover
                    ? '4 Credits'
                    : '10 Credits'
                  : '10 Credits')
              }
              placement='top'
            >
              {canCover || canRecreate ? (
                <ContextualBarSplitButton
                  onMouseEnter={() => {
                    contextualGenerateButtonHoveredRef.current = true;
                  }}
                  onMouseLeave={() => {
                    contextualGenerateButtonHoveredRef.current = false;
                  }}
                  submitText={submitText}
                  isGenerating={isGenerating}
                  disabledReason={disabledReason ?? undefined}
                  currentMenuMode={currentMenuMode}
                  onSubmit={() => {
                    const transactionLogger = createTransactionLogger();
                    logStudioWebUserEvent(
                      {
                        actionName: 'StudioContextualGenerateClicked',
                        context: {
                          contextualGenerateMode: mode,
                        },
                      },
                      transactionLogger
                    );
                    handleSubmit(transactionLogger);
                  }}
                  onSelectMode={(selectedMode) => {
                    setEnableCover(selectedMode === 'cover');
                    setEnableRecreate(selectedMode === 'recreate');
                  }}
                  menuPlacement='top-right'
                  SpinnerComponent={SpinnerSVG}
                  showRecreate={canRecreate}
                  showCover={canCover}
                />
              ) : (
                <MainButton
                  onMouseEnter={() => {
                    contextualGenerateButtonHoveredRef.current = true;
                  }}
                  onMouseLeave={() => {
                    contextualGenerateButtonHoveredRef.current = false;
                  }}
                  variant={ButtonVariant.Aura}
                  shape={ButtonShape.Pill}
                  disabled={isGenerating || !!disabledReason}
                  icon={isGenerating ? <SpinnerSVG /> : <CreateIcon />}
                  onClick={() => {
                    const transactionLogger = createTransactionLogger();
                    logStudioWebUserEvent(
                      {
                        actionName: 'StudioContextualGenerateClicked',
                        context: {
                          contextualGenerateMode: mode,
                        },
                      },
                      transactionLogger
                    );
                    handleSubmit(transactionLogger);
                  }}
                >
                  {submitText}
                </MainButton>
              )}
            </Tooltip>
          </>
        )}
      </Wrapper>
    </Positioner>
  );
}
