import styled from '@emotion/styled';
import { useStatsigClient } from '@statsig/react-bindings';
import { observer } from 'mobx-react-lite';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useLocalStorage } from 'usehooks-ts';

import { useStores } from '@/app/(root)/AppProviders';
import { toast } from '@/components/toast/Toast';
import useClip, { fetchClip } from '@/hooks/useClip';
import { PromptType, ReferenceType } from '@/hooks/useGenerate';
import {
  CheckboxIcon,
  CheckboxOutlineIcon,
  ExtendRightIcon,
  GearIcon,
  SectionIcon,
} from '@/icons';
import logWebUserEvent, {
  TransactionLogger,
  createTransactionLogger,
} from '@/logging/logWebUserEvent';
import { PlanFeature } from '@/state/sessionStore';
import { MAX_CUSTOM_PROMPT_CHARS_LONG } from '@/utils/constants';
import { isFeatureEnabledForPlan } from '@/utils/session';
import snap from '@/utils/snap';
import { decodeTimeFormat, encodeTimeFormat, sleep } from '@/utils/utils';

import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '../button/Button';
import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '../contextMenu/ContextMenu';
import SpinnerSVG from '../svg/SpinnerSVG';
import { Tooltip } from '../tooltip/Tooltip';
import EditModeContext, { getAnalyticsToolName } from './EditModeContext';
import EditStylesContext from './EditStylesContext';
import GenerateContext from './GenerateContext';
import PreviewClipContext from './PreviewClipContext';
import SelectionContext, { getEditCategory } from './SelectionContext';
import getEditHint from './getEditHint';
import { getEditType } from './getEditType';
import AlignedLyricsContext from './lyrics/AlignedLyricsContext';
import { getPlaintextLyrics } from './lyrics/getPlaintextLyrics';

const Wrapper = styled.div<{ fadeOut: boolean }>`
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  background-color: rgba(0, 0, 0, 0.2);
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  height: 100%;
  box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 2;
  > * {
    opacity: ${({ fadeOut }) => (fadeOut ? 0 : 1)};
    transition: opacity 0.4s;
  }
`;

const HintWrapper = styled.div`
  display: flex;
  align-items: center;
  gap: 40px;
  padding: 0 20px;
  height: 100%;
`;

const UpsellWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 0 20px;
  height: 100%;
  width: 100%;
`;

const ControlsWrapper = styled.div`
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 10px;
  height: 100%;
`;

const TimeInput = styled.input`
  font-family: 'Input Sans', monospace;
  font-size: 14px;

  background-color: transparent;
  border: 1px solid rgba(255, 255, 255, 0.1);

  border-radius: 4px;
  padding: 5px;
  width: 100px;
`;

export default observer(function EditToolbar({
  clipId,
  fadeOut,
}: {
  clipId: string;
  fadeOut: boolean;
}) {
  const { clip } = useClip(clipId);
  const clipDuration = useMemo(() => clip?.metadata?.duration, [clip]);
  const { editMode, setEditMode, setLastAppliedEditType } =
    useContext(EditModeContext);
  const { styles, negativeStyles } = useContext(EditStylesContext);
  const {
    previewClip,
    songEndSeconds,
    setPreviewEdit,
    applyPreviewEdit,
    applying,
    setApplying,
  } = useContext(PreviewClipContext);
  const statsigClient = useStatsigClient();
  const shortClipPricingEnabled =
    !!statsigClient?.checkGate('short-clip-pricing');

  const {
    selectionStartSeconds,
    selectionEndSeconds,
    setSelectionStartSeconds,
    setSelectionEndSeconds,
  } = useContext(SelectionContext);

  const { generateMutation, modelTier, modelOverride } =
    useContext(GenerateContext);
  const {
    userLyrics,
    songLyrics,
    startReplacementConfirmation,
    setReplacementConfirmation,
    replacementConfirmation,
    refetchClipLyrics,
    exportExtendLyrics,
    exportReplaceLyrics,
    setSkipAugmentation,
  } = useContext(AlignedLyricsContext);
  const { project, edit, clips, session } = useStores();
  const [manualLyricsReplacement, setManualLyricsReplacement] = useLocalStorage(
    `edit-manual-lyrics-replacement-feb-13-2025`,
    false
  );
  const [keepDuration, setKeepDuration] = useState(true);
  const [actuallyKeepDuration, setActuallyKeepDuration] = useState(
    Boolean(session.flags?.['diffusion-infill'])
  );
  useEffect(() => {
    setActuallyKeepDuration(Boolean(session.flags?.['diffusion-infill']));
  }, [session.flags?.['diffusion-infill']]);
  const [instrumentalReplace, setInstrumentalReplace] = useState(false);

  const handleConfirmReplacementLyrics = useCallback(() => {
    startReplacementConfirmation(
      songLyrics,
      userLyrics,
      selectionStartSeconds,
      selectionEndSeconds
    );
  }, [
    songLyrics,
    userLyrics,
    selectionStartSeconds,
    selectionEndSeconds,
    startReplacementConfirmation,
  ]);

  const handleReplace = useCallback(
    async (transactionLogger: TransactionLogger) => {
      if (!clipDuration) return;
      const infillStart = snap(
        Math.max(0, selectionStartSeconds),
        1 / 25,
        'floor'
      );

      const infillEnd = snap(
        Math.min(selectionEndSeconds, clipDuration - 1 / 25),
        1 / 25,
        'ceil'
      );

      const actuallyActuallyKeepDuration =
        actuallyKeepDuration && infillEnd - infillStart < 20;

      const contextExpansion = actuallyActuallyKeepDuration
        ? (30 - (infillEnd - infillStart)) / 2
        : styles === clip!.metadata?.tags
          ? 30
          : 5;

      const contextStart = snap(
        Math.max(0, selectionStartSeconds - contextExpansion),
        1 / 25,
        'floor'
      );
      const contextEnd = actuallyActuallyKeepDuration
        ? contextStart + 30
        : snap(
            Math.min(
              selectionEndSeconds + contextExpansion,
              clipDuration - 1 / 25
            ),
            1 / 25,
            'ceil'
          );

      const exportedLyrics = exportReplaceLyrics(contextStart, contextEnd);

      try {
        await generateMutation.mutateAsync({
          transactionLogger,
          editSessionId: edit.editSessionId || undefined,
          projectId: project.userSelectedProjectId || undefined,
          prompt: {
            type: PromptType.Custom,
            tags: styles || '',
            negativeTags: negativeStyles || '',
            title: clip!.title,
            lyrics: instrumentalReplace
              ? undefined
              : exportedLyrics.fullPlaintextLyricsAfterEdit.slice(
                  0,
                  MAX_CUSTOM_PROMPT_CHARS_LONG
                ),
          },
          modelTier,
          modelOverride: modelOverride || undefined,
          references: [
            {
              type: actuallyActuallyKeepDuration
                ? ReferenceType.FixedInfill
                : ReferenceType.Infill,
              clipId: clipId,
              startSeconds: infillStart,
              endSeconds: infillEnd,
              durationSeconds: keepDuration
                ? snap(infillEnd - infillStart, 1 / 25)
                : undefined,
              contextStartSeconds: contextStart,
              contextEndSeconds: contextEnd,
              contextLyrics: instrumentalReplace
                ? ''
                : exportedLyrics.contextPlaintextLyricsAfterEdit.slice(
                    0,
                    MAX_CUSTOM_PROMPT_CHARS_LONG
                  ),
              infillLyrics: instrumentalReplace
                ? ''
                : exportedLyrics.selectedPlaintextLyricsAfterEdit.slice(
                    0,
                    MAX_CUSTOM_PROMPT_CHARS_LONG
                  ),
              lyricsUpdated:
                !instrumentalReplace &&
                exportedLyrics.selectedPlaintextLyricsAfterEdit !==
                  exportedLyrics.selectedPlaintextLyricsBeforeEdit,
            },
          ],
        });
      } catch (e) {
        toast({
          title: 'Replace Error',
          description: `Please try again later, or contact us if this problem persists.`,
          status: 'error',
          duration: 5000,
          isClosable: true,
        });
      }
    },
    [
      modelTier,
      instrumentalReplace,
      keepDuration,
      edit.editSessionId,
      clipDuration,
      clipId,
      styles,
      negativeStyles,
      userLyrics,
      generateMutation.mutateAsync,
      selectionEndSeconds,
      selectionStartSeconds,
      project.userSelectedProjectId,
      replacementConfirmation,
      modelOverride,
      actuallyKeepDuration,
    ]
  );

  const handleExtend = useCallback(
    async (transactionLogger: TransactionLogger) => {
      if (!clipDuration) return;
      const extendStart = snap(
        Math.max(0, selectionStartSeconds),
        1 / 25,
        'floor'
      );

      const exportedLyrics = exportExtendLyrics(selectionStartSeconds);

      try {
        await generateMutation.mutateAsync({
          transactionLogger,
          editSessionId: edit.editSessionId || undefined,
          projectId: project.userSelectedProjectId || undefined,
          prompt: {
            type: PromptType.Custom,
            tags: styles || '',
            negativeTags: negativeStyles || '',
            title: clip!.title,
            lyrics: exportedLyrics.postExtendPlaintextLyricsAfterEdit.slice(
              0,
              MAX_CUSTOM_PROMPT_CHARS_LONG
            ),
          },
          modelTier,
          modelOverride: modelOverride || undefined,
          references: [
            {
              // type: ReferenceType.InfillCover,
              // coverClipId: song.id,
              // infillClipId: song.id,
              type: ReferenceType.Extend,
              clipId: clipId,
              startSeconds: extendStart,
              isUpload: clip?.metadata?.type === 'upload',
              contextLyrics:
                exportedLyrics.preExtendPlaintextLyricsAfterEdit.slice(
                  -MAX_CUSTOM_PROMPT_CHARS_LONG
                ),
              lyricsUpdated:
                exportedLyrics.postExtendPlaintextLyricsAfterEdit !==
                exportedLyrics.postExtendPlaintextLyricsBeforeEdit,
            },
          ],
        });
      } catch (e) {
        toast({
          title: 'Extend Error',
          description: `Please try again later, or contact us if this problem persists.`,
          status: 'error',
          duration: 5000,
          isClosable: true,
        });
      }
    },
    [
      modelTier,
      edit.editSessionId,
      clipDuration,
      clipId,
      styles,
      negativeStyles,
      userLyrics,
      generateMutation.mutateAsync,
      selectionEndSeconds,
      selectionStartSeconds,
      project.userSelectedProjectId,
      modelOverride,
    ]
  );

  const handleCrop = useCallback(
    async (isCropRemove: boolean) => {
      setApplying(true);
      setLastAppliedEditType(isCropRemove ? 'remove' : 'crop');
      try {
        const response = await edit.apiClient.POST(
          `/api/edit/crop/{clip_id}/`,
          {
            params: {
              path: {
                clip_id: clipId,
              },
            },
            body: {
              project_id: project.userSelectedProjectId || undefined,
              crop_start_s: selectionStartSeconds,
              crop_end_s: selectionEndSeconds,
              is_crop_remove: isCropRemove,
              edit_session_id: edit.editSessionId,
            },
          }
        );
        if (response.data?.action_clip_id) {
          await sleep(6000);
          window.history.pushState(
            {},
            '',
            `/edit-legacy/${response.data.action_clip_id}`
          );
        } else {
          throw new Error('No action clip ID returned');
        }
      } catch (e) {
        toast({
          title: 'Crop Error',
          description: `Please try again later, or contact us if this problem persists.`,
          status: 'error',
          duration: 5000,
          isClosable: true,
        });
      } finally {
        setApplying(false);
      }
    },
    [selectionStartSeconds, selectionEndSeconds, edit.editSessionId, clipId]
  );

  const handleFadeOut = useCallback(async () => {
    setApplying(true);
    setLastAppliedEditType('fadeOut');
    try {
      const response = await edit.apiClient.POST(`/api/edit/fade/{clip_id}/`, {
        params: {
          path: {
            clip_id: clipId,
          },
        },
        body: {
          project_id: project.userSelectedProjectId || undefined,
          fade_out_time: selectionStartSeconds,
          edit_session_id: edit.editSessionId,
        },
      });
      if (response.data?.action_clip_id) {
        await new Promise<void>((resolve) => {
          const interval = setInterval(async () => {
            try {
              const clip = await fetchClip(clips, response.data.action_clip_id);
              if (clip?.status) {
                clearInterval(interval);
                resolve();
              }
            } catch (e) {}
          }, 2000);
        });
        window.history.pushState(
          {},
          '',
          `/edit-legacy/${response.data.action_clip_id}`
        );
      } else {
        throw new Error('No action clip ID returned');
      }
    } catch (e) {
      toast({
        title: 'Fade Error',
        description: `Please try again later, or contact us if this problem persists.`,
        status: 'error',
        duration: 5000,
        isClosable: true,
      });
    } finally {
      setApplying(false);
    }
  }, [selectionStartSeconds, songEndSeconds, edit.editSessionId, clipId]);

  const [selectionStartPlaintext, setSelectionStartPlaintext] = useState(
    () => encodeTimeFormat(selectionStartSeconds, 2) || '00:00.00'
  );
  const [selectionEndPlaintext, setSelectionEndPlaintext] = useState(
    () => encodeTimeFormat(selectionEndSeconds, 2) || '00:00.00'
  );

  useEffect(() => {
    setSelectionStartPlaintext(
      encodeTimeFormat(selectionStartSeconds, 2) || '00:00.00'
    );
    setSelectionEndPlaintext(
      encodeTimeFormat(selectionEndSeconds, 2) || '00:00.00'
    );
  }, [selectionStartSeconds, selectionEndSeconds]);

  const [aligningLyrics, setAligningLyrics] = useState(false);
  const handleAlignLyrics = useCallback(async () => {
    if (!clip) return;
    setAligningLyrics(true);
    try {
      const plaintextLyrics = getPlaintextLyrics(userLyrics);
      await clips.setClipPrompt(clipId, plaintextLyrics, clip.model_name);
      setSkipAugmentation(true);
    } finally {
      setAligningLyrics(false);
    }
  }, [
    userLyrics,
    refetchClipLyrics,
    setSkipAugmentation,
    clips.setClipPrompt,
    session,
  ]);

  const generating = aligningLyrics || generateMutation.isPending || applying;
  const previewing = Boolean(previewClip);

  const willConfirmReplacement =
    manualLyricsReplacement &&
    !instrumentalReplace &&
    userLyrics.filter((l) => l.text.trim()).length > 0;

  useEffect(() => {
    setReplacementConfirmation(null);
  }, [editMode]);

  if (!isFeatureEnabledForPlan(session, PlanFeature.EditMode)) {
    return (
      <Wrapper fadeOut={fadeOut}>
        <UpsellWrapper>
          <Button href='/account' variant={ButtonVariant.Primary}>
            Subscribe
          </Button>
          to enable editing tools
        </UpsellWrapper>
      </Wrapper>
    );
  }

  if (previewing) {
    return (
      <Wrapper fadeOut={fadeOut}>
        <HintWrapper>
          Apply edit for improved consistency and transitions.
        </HintWrapper>
        <ControlsWrapper>
          <Button
            variant={ButtonVariant.Tertiary}
            size={ButtonSize.Medium}
            shape={ButtonShape.Pill}
            onClick={() => setPreviewEdit(null)}
          >
            Cancel Preview
          </Button>
          <Button
            variant={applying ? ButtonVariant.Standard : ButtonVariant.Primary}
            disabled={applying}
            size={ButtonSize.Medium}
            shape={ButtonShape.Pill}
            icon={
              applying ? (
                <SpinnerSVG />
              ) : getEditType(previewClip!) === 'replace' ? (
                <SectionIcon />
              ) : (
                <ExtendRightIcon />
              )
            }
            onClick={() => {
              if (previewClip) {
                logWebUserEvent({
                  actionName: 'ApplyEdit',
                  context: {
                    insertedClipId: previewClip.id,
                    editTool: getAnalyticsToolName(
                      getEditType(previewClip) || 'none'
                    ),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });
              }
              applyPreviewEdit();
            }}
          >
            Apply{' '}
            {getEditType(previewClip!) === 'replace'
              ? 'Replacement'
              : 'Extension'}
          </Button>
        </ControlsWrapper>
      </Wrapper>
    );
  }

  if (replacementConfirmation) {
    return (
      <Wrapper fadeOut={fadeOut}>
        <HintWrapper>
          Fine-tune the lyrics to replace in the area above.
        </HintWrapper>
        <ControlsWrapper>
          <Button
            variant={ButtonVariant.Tertiary}
            size={ButtonSize.Medium}
            shape={ButtonShape.Pill}
            onClick={() => {
              setReplacementConfirmation(null);
              logWebUserEvent({
                actionName: 'CancelConfirmLyricsReplacement',
                context: {
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });
            }}
          >
            Cancel
          </Button>

          <Button
            disabled={generating || previewing}
            size={ButtonSize.Medium}
            variant={ButtonVariant.Aura}
            shape={ButtonShape.Pill}
            icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
            onClick={() => {
              const transactionLogger = createTransactionLogger();
              transactionLogger.logWebUserEvent({
                actionName: 'GenerateButtonClicked',
                context: {
                  onebox: false,
                  isEdit: true,
                  editTool: getAnalyticsToolName(editMode),
                },
              });
              transactionLogger.logWebUserEvent({
                actionName: 'ConfirmLyricsReplacement',
                context: {
                  lyrics: replacementConfirmation.replacementLyrics,
                  continuedAlignedPrompt:
                    getPlaintextLyrics(
                      replacementConfirmation.originalLyricsSplit[0].map(
                        (x) => x.lyric
                      )
                    ) +
                    replacementConfirmation.replacementLyrics +
                    getPlaintextLyrics(
                      replacementConfirmation.originalLyricsSplit[2].map(
                        (x) => x.lyric
                      )
                    ),
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });
              transactionLogger.logWebUserEvent({
                actionName: 'SubmitEditModeAction',
                context: {
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });
              handleReplace(transactionLogger);
            }}
          >
            Confirm & Generate
          </Button>
        </ControlsWrapper>
      </Wrapper>
    );
  }

  return (
    <Wrapper fadeOut={fadeOut}>
      <HintWrapper>
        {getEditHint(editMode, selectionStartSeconds, selectionEndSeconds)}
      </HintWrapper>
      <ControlsWrapper>
        {editMode === 'replace' && (
          <ContextMenuTrigger
            title='Replace Settings'
            ButtonComponent={(props) => (
              <Button
                {...props}
                variant={ButtonVariant.Tertiary}
                size={ButtonSize.Medium}
                icon={<GearIcon />}
              />
            )}
            ContentsComponent={() => (
              <>
                <Tooltip
                  label='Encourage replacements to maintain timing of the original selection.'
                  placement='left'
                >
                  <ContextMenuItem
                    keepMenusOpen
                    icon={
                      keepDuration ? (
                        <CheckboxIcon className='h-4 w-4' />
                      ) : (
                        <CheckboxOutlineIcon className='h-4 w-4' />
                      )
                    }
                    onClick={() => {
                      setKeepDuration((prev) => !prev);
                      logWebUserEvent({
                        actionName: 'UpdateDurationControl',
                        context: {
                          editTool: getAnalyticsToolName(editMode),
                          editSessionId:
                            edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                          editingClipId: clipId,
                          isFixedDuration: !keepDuration,
                          actionIndex: -1, // todo?
                        },
                      });
                    }}
                  >
                    Keep Duration
                  </ContextMenuItem>
                </Tooltip>
                {keepDuration && session.flags?.['diffusion-infill'] && (
                  <Tooltip
                    label='Enables an experimental fixed-duration mode that is incapable of shortening or lengthening the duration of the replacement.'
                    placement='left'
                  >
                    <ContextMenuItem
                      keepMenusOpen
                      icon={
                        actuallyKeepDuration ? (
                          <CheckboxIcon className='h-4 w-4' />
                        ) : (
                          <CheckboxOutlineIcon className='h-4 w-4' />
                        )
                      }
                      onClick={() => {
                        setActuallyKeepDuration((prev) => !prev);
                      }}
                    >
                      Actually Keep Duration
                    </ContextMenuItem>
                  </Tooltip>
                )}
                <Tooltip
                  label='Discourage lyrics or human speech in replacements.'
                  placement='left'
                >
                  <ContextMenuItem
                    keepMenusOpen
                    icon={
                      instrumentalReplace ? (
                        <CheckboxIcon className='h-4 w-4' />
                      ) : (
                        <CheckboxOutlineIcon className='h-4 w-4' />
                      )
                    }
                    onClick={() => {
                      setInstrumentalReplace((prev) => !prev);
                      logWebUserEvent({
                        actionName: 'UpdateInstrumental',
                        context: {
                          editTool: getAnalyticsToolName(editMode),
                          editSessionId:
                            edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                          editingClipId: clipId,
                          isInstrumental: !instrumentalReplace,
                          actionIndex: -1, // todo?
                        },
                      });
                    }}
                  >
                    Instrumental
                  </ContextMenuItem>
                </Tooltip>
                <Tooltip
                  label='Adds a step to fine-tune which lyrics are replaced.'
                  placement='left'
                >
                  <ContextMenuItem
                    icon={
                      manualLyricsReplacement ? (
                        <CheckboxIcon className='h-4 w-4' />
                      ) : (
                        <CheckboxOutlineIcon className='h-4 w-4' />
                      )
                    }
                    onClick={() => {
                      setManualLyricsReplacement((prev) => !prev);
                      logWebUserEvent({
                        actionName: 'UpdateManualLyricsReplacementEnabled',
                        context: {
                          editTool: getAnalyticsToolName(editMode),
                          editSessionId:
                            edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                          editingClipId: clipId,
                          isManualLyricsReplacementEnabled:
                            !manualLyricsReplacement,
                          actionIndex: -1, // todo?
                        },
                      });
                    }}
                  >
                    Manual lyrics replacement
                  </ContextMenuItem>
                </Tooltip>
              </>
            )}
          />
        )}
        {getEditCategory(editMode) === 'end-fixed' && <>From</>}
        {getEditCategory(editMode) !== 'no-selection' && (
          <TimeInput
            disabled={generating || previewing}
            value={selectionStartPlaintext}
            onChange={(e) => setSelectionStartPlaintext(e.target.value)}
            onBlur={() => {
              const seconds = decodeTimeFormat(selectionStartPlaintext);
              if (seconds !== null) {
                setSelectionStartSeconds(seconds);
                logWebUserEvent({
                  actionName: 'MakeWaveformSelection',
                  context: {
                    startSeconds: seconds,
                    endSeconds: selectionEndSeconds,
                    editTool: getAnalyticsToolName(editMode),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                    inputType: 'start-input',
                  },
                });
              } else {
                setSelectionStartPlaintext(
                  encodeTimeFormat(selectionStartSeconds, 2) || '00:00.00'
                );
              }
            }}
          />
        )}
        {getEditCategory(editMode) !== 'no-selection' &&
          getEditCategory(editMode) !== 'end-fixed' && (
            <>
              &mdash;
              <TimeInput
                disabled={generating || previewing}
                value={selectionEndPlaintext}
                onChange={(e) => setSelectionEndPlaintext(e.target.value)}
                onBlur={() => {
                  const seconds = decodeTimeFormat(selectionEndPlaintext);
                  if (seconds !== null) {
                    setSelectionEndSeconds(seconds);
                    logWebUserEvent({
                      actionName: 'MakeWaveformSelection',
                      context: {
                        startSeconds: selectionStartSeconds,
                        endSeconds: seconds ?? selectionEndSeconds,
                        editTool: getAnalyticsToolName(editMode),
                        editSessionId:
                          edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                        editingClipId: clipId,
                        actionIndex: -1, // todo?
                        inputType: 'end-input',
                      },
                    });
                  } else {
                    setSelectionEndPlaintext(
                      encodeTimeFormat(selectionEndSeconds, 2) || '00:00.00'
                    );
                  }
                }}
              />
            </>
          )}
        {editMode === 'replace' && (
          <Tooltip
            label={
              shortClipPricingEnabled &&
              typeof selectionEndSeconds === 'number' &&
              typeof selectionStartSeconds === 'number' &&
              selectionEndSeconds - selectionStartSeconds < 30
                ? '4 Credits'
                : undefined
            }
            placement='top'
          >
            <Button
              className='whitespace-nowrap'
              disabled={generating || previewing}
              size={ButtonSize.Medium}
              variant={ButtonVariant.Aura}
              shape={ButtonShape.Pill}
              icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
              onClick={() => {
                if (willConfirmReplacement) {
                  logWebUserEvent({
                    actionName: 'StartLyricsReplacement',
                    context: {
                      editTool: getAnalyticsToolName(editMode),
                      editSessionId:
                        edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                      editingClipId: clipId,
                      actionIndex: -1, // todo?
                    },
                  });
                  handleConfirmReplacementLyrics();
                } else {
                  const transactionLogger = createTransactionLogger();
                  transactionLogger.logWebUserEvent({
                    actionName: 'GenerateButtonClicked',
                    context: {
                      onebox: false,
                      isEdit: true,
                      editTool: getAnalyticsToolName(editMode),
                    },
                  });
                  transactionLogger.logWebUserEvent({
                    actionName: 'SubmitEditModeAction',
                    context: {
                      editTool: getAnalyticsToolName(editMode),
                      editSessionId:
                        edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                      editingClipId: clipId,
                      actionIndex: -1, // todo?
                    },
                  });
                  handleReplace(transactionLogger);
                }
              }}
            >
              Generate Replacements
            </Button>
          </Tooltip>
        )}
        {editMode === 'extend' && (
          <Button
            className='whitespace-nowrap'
            disabled={generating || previewing}
            size={ButtonSize.Medium}
            variant={ButtonVariant.Aura}
            shape={ButtonShape.Pill}
            icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
            onClick={() => {
              const transactionLogger = createTransactionLogger();
              transactionLogger.logWebUserEvent({
                actionName: 'GenerateButtonClicked',
                context: {
                  onebox: false,
                  isEdit: true,
                  editTool: getAnalyticsToolName(editMode),
                },
              });
              transactionLogger.logWebUserEvent({
                actionName: 'SubmitEditModeAction',
                context: {
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });
              handleExtend(transactionLogger);
            }}
          >
            Generate Extensions
          </Button>
        )}
        {editMode === 'crop' && (
          <>
            <Button
              disabled={generating || previewing}
              size={ButtonSize.Medium}
              variant={ButtonVariant.Aura}
              shape={ButtonShape.Pill}
              icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
              onClick={() => {
                logWebUserEvent({
                  actionName: 'SubmitEditModeAction',
                  context: {
                    editTool: getAnalyticsToolName(editMode),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });
                logWebUserEvent({
                  actionName: 'ApplyEdit',
                  context: {
                    editTool: getAnalyticsToolName(editMode),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });

                handleCrop(false);
              }}
            >
              Crop
            </Button>
          </>
        )}
        {editMode === 'remove' && (
          <>
            <Button
              disabled={generating || previewing}
              size={ButtonSize.Medium}
              variant={ButtonVariant.Aura}
              shape={ButtonShape.Pill}
              icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
              onClick={() => {
                logWebUserEvent({
                  actionName: 'SubmitEditModeAction',
                  context: {
                    editTool: getAnalyticsToolName(editMode),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });
                logWebUserEvent({
                  actionName: 'ApplyEdit',
                  context: {
                    editTool: getAnalyticsToolName(editMode),
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });

                handleCrop(true);
              }}
            >
              Remove
            </Button>
          </>
        )}
        {editMode === 'fadeOut' && (
          <Button
            className='whitespace-nowrap'
            disabled={generating || previewing}
            size={ButtonSize.Medium}
            variant={ButtonVariant.Aura}
            shape={ButtonShape.Pill}
            icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
            onClick={() => {
              logWebUserEvent({
                actionName: 'SubmitEditModeAction',
                context: {
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });
              logWebUserEvent({
                actionName: 'ApplyEdit',
                context: {
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId:
                    edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                },
              });

              handleFadeOut();
            }}
          >
            Fade Out
          </Button>
        )}
        {editMode === 'fixLyrics' && (
          <>
            <Button
              size={ButtonSize.Medium}
              variant={ButtonVariant.Tertiary}
              shape={ButtonShape.Pill}
              disabled={generating}
              onClick={() => {
                setEditMode('replace');

                logWebUserEvent({
                  actionName: 'EndLyricsAlignment',
                  context: {
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });
              }}
            >
              Go Back
            </Button>
            <Button
              className='whitespace-nowrap'
              size={ButtonSize.Medium}
              variant={ButtonVariant.Aura}
              shape={ButtonShape.Pill}
              disabled={generating}
              icon={generating ? <SpinnerSVG className='h-5 w-5' /> : null}
              onClick={() => {
                handleAlignLyrics();

                logWebUserEvent({
                  actionName: 'ConfirmLyricsAlignment',
                  context: {
                    editSessionId:
                      edit.editSessionId || 'MISSING_EDIT_SESSION_ID',
                    editingClipId: clipId,
                    actionIndex: -1, // todo?
                  },
                });
              }}
            >
              Confirm & Align Lyrics
            </Button>
          </>
        )}
      </ControlsWrapper>
    </Wrapper>
  );
});
