'use client';

/* eslint jsx-a11y/no-static-element-interactions: warn */
import * as d3 from 'd3';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { twMerge } from 'tailwind-merge';

import { useStores } from '@/app/(root)/AppProviders';
import { CheckIcon } from '@/icons';
import { Clip } from '@/state/clipStore';
import { PLAYBAR_Z_INDEX } from '@/utils/constants';
import { eventLogger } from '@/utils/event-logger';
import { ActionName } from '@/utils/event-names';
import { encodeTimeFormat, quantize } from '@/utils/utils';

import Button, { ButtonShape } from '../button/Button';
import SpinnerSVG from '../svg/SpinnerSVG';

interface D3WaveformProps {
  index?: number;
  clip: Clip;
  className?: string;
  height?: number;
  fillColor?: string;
  strokeColor?: string;
  initialStartValue?: number;
  quantizeSelectionSecs?: number;
  maxSelectionRangeSecs?: number;
  selectionType?: string;
  isDraggingPlaybar?: boolean;
  actionMode?: string;
  setWaveformStartInput: (value: string) => void;
  setWaveformEndInput: (value: string) => void;
  startPosition: number | null;
  endPosition: number | null;
  setStartPosition: (value: number | null) => void;
  setEndPosition: (value: number | null) => void;
  showTimestamps?: boolean;
  actionButtonText?: string;
  onActionButtonClick?: () => void;
  pinEndPosition?: boolean;
  initialStartPosition?: number;
}

const D3Waveform = observer(
  ({
    index,
    clip,
    className,
    height,
    fillColor,
    strokeColor,
    initialStartValue,
    selectionType,
    maxSelectionRangeSecs,
    quantizeSelectionSecs = 0.2,
    isDraggingPlaybar = false,
    actionMode,
    setWaveformStartInput,
    setWaveformEndInput,
    startPosition,
    endPosition,
    setStartPosition,
    setEndPosition,
    showTimestamps = true,
    actionButtonText,
    onActionButtonClick,
    pinEndPosition = false,
    initialStartPosition,
  }: D3WaveformProps) => {
    const { playbar, edit, session, genForm, clips } = useStores();
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const containerRef = useRef<any>(null);
    const svgRef = useRef<any>(null);
    const pathname = usePathname();

    const [drawn, setDrawn] = useState(false);
    const [clipSamples, setClipSamples] = useState<number[]>([]);
    const [isDragging, setIsDragging] = useState(false);
    const [isDraggingSelectionBox, setIsDraggingSelectionBox] = useState(false);
    const [activeDragHandle, setActiveDragHandle] = useState<string | null>(
      null
    );
    const [isShiftPressed, setIsShiftPressed] = useState(false);
    const debounceWaveformMetricTimeout = useRef<any>(null);

    // Note: instead of making everything customizable, this feature flag controls some styles
    // (inner overlay color, drag handles color/hover, existence of outer overlay)
    const isEditModeEnabled = session.flags?.['edit-mode-ui'];

    const [inputStartPosition, setInputStartPosition] = useState<number | null>(
      null
    );
    const [selectionBoxTopOffset, setSelectionBoxTopOffset] = useState<
      number | undefined
    >(undefined);

    // Constants
    const HEIGHT_PIXELS = height || 200;
    const CHUNK_SAMPLES = clip?.metadata?.duration
      ? clip?.metadata?.duration * 15
      : 2000;
    const SCALE_HEIGHT = 1.0;
    const MIN_SELECTION_WIDTH = 10; //in px

    const selectionChange = (e: any) => {
      const roundedStart = quantize(e.start, quantizeSelectionSecs);
      const roundedEnd = quantize(e.end, quantizeSelectionSecs);
      edit.setSelectionRange(roundedStart, roundedEnd);
      setWaveformStartInput(encodeTimeFormat(roundedStart, 1) || '');
      setWaveformEndInput(encodeTimeFormat(roundedEnd, 1) || '');

      if (debounceWaveformMetricTimeout.current !== null) {
        clearTimeout(debounceWaveformMetricTimeout.current);
      }
      debounceWaveformMetricTimeout.current = setTimeout(() => {
        if (
          pathname.startsWith('/edit/') ||
          pathname.startsWith('/edit-legacy/')
        ) {
          edit.incrementActionIndex();
          eventLogger.logAudioCreationEvent(
            false,
            ActionName.makeWaveformSelection,
            genForm,
            session,
            {
              startSeconds: roundedStart,
              endSeconds: roundedEnd,
              editTool: edit.activeEditTool,
              editSessionId: edit.editSessionId,
              editingClipId: edit.editingClipId,
              actionIndex: edit.actionIndex,
            }
          );
        }
      }, 1000);
    };

    const resetSelection = () => {
      setIsDragging(false);
      setStartPosition(null);
      setEndPosition(null);
    };

    useHotkeys('left', () => {
      if (
        edit.isSelectionRangeActive() &&
        clip?.metadata?.duration &&
        containerRef.current
      ) {
        if (activeDragHandle === 'l') {
          const newStart = Math.max(
            0,
            (startPosition || 0) -
              (quantizeSelectionSecs / clip?.metadata?.duration) *
                containerRef.current?.getBoundingClientRect().width
          );
          setStartPosition(newStart);
          if (
            !maxSelectionRangeSecs ||
            (edit.selectionRange?.end || 0) -
              (newStart / containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration <=
              (maxSelectionRangeSecs || 0)
          ) {
            selectionChange({
              start:
                (newStart /
                  containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration,
              end: edit.selectionRange?.end,
            });
          }
        } else if (activeDragHandle === 'r') {
          const newEnd = Math.max(
            (startPosition || 0) + 20,
            (endPosition || 0) -
              (quantizeSelectionSecs / clip?.metadata?.duration) *
                containerRef.current?.getBoundingClientRect().width
          );
          setEndPosition(newEnd);
          if (
            !maxSelectionRangeSecs ||
            (newEnd / containerRef.current.getBoundingClientRect().width) *
              clip?.metadata?.duration -
              (edit.selectionRange?.start || 0) <=
              (maxSelectionRangeSecs || 0)
          ) {
            selectionChange({
              end:
                (newEnd / containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration,
              start: edit.selectionRange?.start,
            });
          }
        }
      }
    });

    useHotkeys('right', () => {
      if (
        edit.isSelectionRangeActive() &&
        clip?.metadata?.duration &&
        containerRef.current
      ) {
        if (activeDragHandle === 'l') {
          const newStart = Math.min(
            (endPosition || 0) - 20,
            (startPosition || 0) +
              (quantizeSelectionSecs / clip?.metadata?.duration) *
                containerRef.current?.getBoundingClientRect().width
          );
          setStartPosition(newStart);
          if (
            !maxSelectionRangeSecs ||
            (edit.selectionRange?.end || 0) -
              (newStart / containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration <=
              (maxSelectionRangeSecs || 0)
          ) {
            selectionChange({
              start:
                (newStart /
                  containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration,
              end: edit.selectionRange?.end,
            });
          }
        } else if (activeDragHandle === 'r') {
          const newEnd = Math.min(
            containerRef.current?.getBoundingClientRect().width,
            (endPosition || 0) +
              (quantizeSelectionSecs / clip?.metadata?.duration) *
                containerRef.current?.getBoundingClientRect().width
          );
          setEndPosition(newEnd);
          if (
            !maxSelectionRangeSecs ||
            (newEnd / containerRef.current.getBoundingClientRect().width) *
              clip.metadata.duration -
              (edit.selectionRange?.start || 0) <=
              (maxSelectionRangeSecs || 0)
          ) {
            selectionChange({
              end:
                (newEnd / containerRef.current.getBoundingClientRect().width) *
                clip?.metadata?.duration,
              start: edit.selectionRange?.start,
            });
          }
        }
      }
    });

    useHotkeys(
      'shift',
      () => {
        setIsShiftPressed(true);
      },
      { keydown: true, keyup: false }
    );

    useHotkeys(
      'shift',
      () => {
        setIsShiftPressed(false);
      },
      { keydown: false, keyup: true }
    );

    useEffect(() => {
      const rectWidth = canvasRef.current?.getBoundingClientRect().width;
      if (
        clip?.metadata?.duration !== null &&
        clip?.metadata?.duration !== undefined &&
        initialStartValue !== undefined &&
        rectWidth !== undefined
      ) {
        const startPos =
          (initialStartValue / clip?.metadata?.duration) * rectWidth;
        setStartPosition(startPos);
      }
    }, [initialStartValue, clip?.metadata?.duration]);

    useEffect(() => {
      const process = async () => {
        setDrawn(false);
        resetSelection();

        if (clips.pregenWaveformByClipId[clip?.id]) {
          const pregenRMS = clips.pregenWaveformByClipId[clip?.id].waveformData;
          const scaleVal = SCALE_HEIGHT / Math.max(...pregenRMS);
          setClipSamples(pregenRMS.map((s) => s * scaleVal));
          return;
        }

        let audioDataForClip: AudioBuffer | null | undefined =
          playbar.audioData[clip?.id];
        if (!audioDataForClip || drawn) {
          audioDataForClip = await playbar.decodeAudio(clip);
        }

        if (!audioDataForClip) {
          return;
        }
        const left = audioDataForClip.getChannelData(0);
        const right =
          audioDataForClip.numberOfChannels > 1
            ? audioDataForClip.getChannelData(1)
            : new Float32Array([...left]);

        // Break down decoded audio into chunks and take root-mean-squared of each chunk
        const numSamples = Math.floor(left.length / CHUNK_SAMPLES);
        const sampleRMS = Array.from(Array(numSamples).keys()).map(
          (index: number) => {
            const leftSamples = left.slice(
              index * CHUNK_SAMPLES,
              (index + 1) * CHUNK_SAMPLES
            );
            const rightSamples = right.slice(
              index * CHUNK_SAMPLES,
              (index + 1) * CHUNK_SAMPLES
            );
            const leftSum = leftSamples
              .map((ls: number) => ls ** 2)
              .reduce((a: number, b: number) => a + b, 0);
            const rightSum = rightSamples
              .map((rs: number) => rs ** 2)
              .reduce((a: number, b: number) => a + b, 0);
            return Math.sqrt((leftSum + rightSum) / (CHUNK_SAMPLES * 2));
          }
        );

        clips.pregenWaveformByClipId[clip?.id] = {
          waveformData: sampleRMS,
          hootErrorRate: null,
        };
        const scaleVal = SCALE_HEIGHT / Math.max(...sampleRMS);
        setClipSamples(sampleRMS.map((s) => s * scaleVal));
      };
      if (!clips.isLoadingAlignedLyrics) {
        process();
      }
    }, [clip, clips.isLoadingAlignedLyrics]);

    useEffect(() => {
      if (initialStartPosition && clip?.metadata?.duration) {
        setStartPosition(
          (initialStartPosition / clip?.metadata?.duration) *
            containerRef.current.getBoundingClientRect().width
        );
      }
      if (pinEndPosition) {
        setEndPosition(containerRef.current.getBoundingClientRect().width);
      }
    }, [pinEndPosition, initialStartPosition, clip?.metadata?.duration]);

    const drawWaveform = () => {
      const xScale = d3
        .scaleLinear()
        .domain([0, clipSamples.length])
        .range([0, containerRef.current?.getBoundingClientRect().width]);

      const topYScale = d3
        .scaleLinear()
        .domain([0, Math.max(...clipSamples)])
        .range([(height || 0) / 2, height || 0]);

      const bottomYScale = d3
        .scaleLinear()
        .domain([0, Math.max(...clipSamples)])
        .range([(height || 0) / 2, height || 0]);

      const area = d3
        .area()
        .x((d: any) => xScale(d.x))
        .y0((d: any) => topYScale(d.y))
        .y1((d: any) => bottomYScale(-1 * d.y))
        .curve(d3.curveCatmullRom);

      const line = d3
        .line()
        .x((d: any) => xScale(d.x))
        .y((d: any) => topYScale(d.y))
        .curve(d3.curveCatmullRom);

      const negativeLine = d3
        .line()
        .x((d: any) => xScale(d.x))
        .y((d: any) => bottomYScale(-1 * d.y))
        .curve(d3.curveCatmullRom);

      d3.select(`#demo${index || ''}`)
        .selectAll('path')
        .remove();

      const defs = d3.select(`#demo${index || ''}`).append('defs');

      const linearGradient = defs
        .append('linearGradient')
        .attr('id', 'linear-gradient');

      linearGradient
        .attr('x1', '0%')
        .attr('y1', '0%')
        .attr('x2', '0%')
        .attr('y2', '100%');

      linearGradient
        .append('stop')
        .attr('offset', '0%')
        .attr('stop-color', 'rgba(250, 247, 245, 0.1)');

      linearGradient
        .append('stop')
        .attr('offset', '40%')
        .attr('stop-color', 'rgba(250, 247, 245, 0.3)');

      linearGradient
        .append('stop')
        .attr('offset', '50%')
        .attr('stop-color', 'rgba(250, 247, 245, 0.32)');

      linearGradient
        .append('stop')
        .attr('offset', '60%')
        .attr('stop-color', 'rgba(250, 247, 245, 0.3)');

      linearGradient
        .append('stop')
        .attr('offset', '100%')
        .attr('stop-color', 'rgba(250, 247, 245, 0.1)');

      d3.select(`#demo${index || ''}`)
        .append('path')
        .attr(
          'd',
          area(
            clipSamples.map((sample: number, index: number) => ({
              x: index,
              y: sample,
            })) as any
          )
        )
        .attr('pointer-events', 'none')
        .attr('fill', fillColor || '#FAF7F5')
        .attr('stroke', 'none');

      d3.select(`#demo${index || ''}`)
        .append('path')
        .attr(
          'd',
          line(
            clipSamples.map((sample: number, index: number) => ({
              x: index,
              y: sample,
            })) as any
          )
        )
        .attr('pointer-events', 'none')
        .attr('fill', 'none')
        .attr('stroke', strokeColor || 'rgb(250, 247, 245, 0.6)')
        .attr('stroke-width', '1');

      d3.select(`#demo${index || ''}`)
        .append('path')
        .attr(
          'd',
          negativeLine(
            clipSamples.map((sample: number, index: number) => ({
              x: index,
              y: sample,
            })) as any
          )
        )
        .attr('pointer-events', 'none')
        .attr('fill', 'none')
        .attr('stroke', strokeColor || 'rgb(250, 247, 245, 0.6)')
        .attr('stroke-width', '1');
    };

    useEffect(() => {
      drawWaveform();
    }, [clipSamples]);

    useEffect(() => {
      // Prevent highlighting on the page when scrubbing edit mode + dragging selection
      if (isDragging || edit.isScrubbing || isDraggingSelectionBox) {
        document.body.classList.add('no-drag');
      } else {
        document.body.classList.remove('no-drag');
      }
    }, [isDragging, isDraggingSelectionBox, edit.isScrubbing]);

    useEffect(() => {
      const handleResize = () => {
        if (isDragging) return;
        const containerWidth =
          containerRef.current?.getBoundingClientRect().width;
        if (containerWidth && clip?.metadata?.duration) {
          if (startPosition !== null && !!edit.selectionRange?.start) {
            setStartPosition(
              (edit.selectionRange?.start / clip?.metadata?.duration) *
                containerWidth
            );
          }
          if (endPosition !== null && !!edit.selectionRange?.end) {
            setEndPosition(
              (edit.selectionRange?.end / clip?.metadata?.duration) *
                containerWidth
            );
          }
        }
        drawWaveform();
      };

      const resizeObserver = new ResizeObserver(handleResize);
      resizeObserver.observe(containerRef.current);

      return () => {
        if (containerRef.current)
          resizeObserver.unobserve(containerRef.current);
        resizeObserver.disconnect();
      };
    }, [
      clipSamples,
      startPosition,
      endPosition,
      clip?.metadata?.duration,
      isDragging,
    ]);

    useEffect(() => {
      const topOffset = HEIGHT_PIXELS * ((1 - SCALE_HEIGHT) / 2);
      if (topOffset !== selectionBoxTopOffset) {
        setSelectionBoxTopOffset(topOffset);
      }
    }, [startPosition, canvasRef.current?.offsetLeft]);

    useEffect(() => {
      if (edit.selectionRange === null) {
        setStartPosition(null);
        setEndPosition(null);
        setWaveformStartInput('00:00.0');
        setWaveformEndInput('00:00.0');
      } else {
        if (!containerRef.current || !clip?.metadata?.duration) {
          return;
        }
        const width = containerRef.current.getBoundingClientRect().width;
        setStartPosition(
          (edit.selectionRange.start / clip?.metadata?.duration) * width
        );
        setEndPosition(
          (edit.selectionRange.end / clip?.metadata?.duration) * width
        );
        setWaveformStartInput(
          encodeTimeFormat(edit.selectionRange.start, 1) || ''
        );
        setWaveformEndInput(encodeTimeFormat(edit.selectionRange.end, 1) || '');
      }
    }, [edit.selectionRange, actionMode]);

    const handleMoveSelectionBox = (e: any) => {
      const x = e.clientX;
      const boundingRect = containerRef.current?.getBoundingClientRect();
      const currentDelta = x - (edit.selectionBoxDragStart || 0);
      const newStart =
        (edit.selectionBoxPositionStart?.startPosition || 0) + currentDelta;
      const newEnd =
        (edit.selectionBoxPositionStart?.endPosition || 0) + currentDelta;
      const correction =
        newStart < 0
          ? -1 * newStart
          : newEnd > boundingRect.width
            ? boundingRect.width - newEnd
            : 0;
      setStartPosition(newStart + correction);
      setEndPosition(newEnd + correction);
      const duration = clip?.metadata?.duration || 0;
      const durations: any = {};
      durations.start =
        ((newStart + correction) / boundingRect.width) * duration;
      durations.end = ((newEnd + correction) / boundingRect.width) * duration;
      selectionChange(durations);
    };

    return (
      <div
        className={twMerge('h-auto w-auto py-4', className)}
        id='outerouter'
        onMouseMove={(e: any) => {
          if (isDraggingSelectionBox) {
            handleMoveSelectionBox(e);
            return;
          }
          if (isDragging || edit.isScrubbing) {
            const durations: any = {};
            const boundingRect = e.target.getBoundingClientRect();
            const duration = clip?.metadata?.duration || 0;
            const newEndPosition = e.clientX - boundingRect.x;
            const quantizedPosition =
              (quantize(
                (newEndPosition / boundingRect.width) * (duration || 0),
                quantizeSelectionSecs
              ) /
                (duration || 1)) *
              boundingRect.width;

            if (edit.isScrubbing) {
              //playbar.userSetCurrentProgress(
              //  (newEndPosition / boundingRect.width) * 100
              //);

              edit.setScrubPosition(newEndPosition);
              return;
            }
            if (activeDragHandle) {
              let newStart = startPosition || 0;
              let newEnd = endPosition || 0;
              if (activeDragHandle === 'l') {
                newStart = Math.max(0, Math.min(quantizedPosition, newEnd));
              } else {
                newEnd = Math.max(quantizedPosition, newStart);
              }
              // Enforce maxSelectionRangeSecs
              if (maxSelectionRangeSecs) {
                const maxWidth =
                  (maxSelectionRangeSecs / duration) * boundingRect.width;
                if (newEnd - newStart > maxWidth) {
                  if (activeDragHandle === 'l') {
                    newStart = newEnd - maxWidth;
                  } else {
                    newEnd = newStart + maxWidth;
                  }
                }
              }

              setStartPosition(Math.max(newStart, 0));
              setEndPosition(Math.min(newEnd, boundingRect.width));

              const qDuration = quantize(duration, quantizeSelectionSecs);
              const quantizeDuration =
                qDuration > duration
                  ? qDuration - quantizeSelectionSecs
                  : qDuration;

              durations.start = Math.max(
                (newStart / boundingRect.width) * duration,
                0
              );
              durations.end = Math.min(
                (newEnd / boundingRect.width) * duration,
                quantizeDuration
              );
              selectionChange(durations);
              return;
            }

            // enforce the selection being at most maxSelectionRangeSecs
            const start = Math.min(
              Math.max(
                quantizedPosition,
                !!inputStartPosition && clip?.metadata?.duration
                  ? inputStartPosition -
                      ((maxSelectionRangeSecs || clip.metadata?.duration) /
                        clip.metadata?.duration) *
                        boundingRect.width
                  : 0
              ),
              inputStartPosition || 0
            );
            const quantizedEnd = Math.min(
              quantizedPosition,
              !!inputStartPosition && clip?.metadata?.duration
                ? inputStartPosition +
                    ((maxSelectionRangeSecs || clip?.metadata?.duration) /
                      clip?.metadata?.duration) *
                      boundingRect.width
                : 0
            );

            //const end = pinStartToZero
            //  ? quantizedEnd
            //  : Math.max(quantizedEnd, inputStartPosition || 0);

            const end = Math.max(quantizedEnd, inputStartPosition || 0);
            if (selectionType === 'range') {
              durations.start =
                (start / boundingRect.width) * (clip?.metadata?.duration || 0);
              durations.end = pinEndPosition
                ? clip?.metadata?.duration
                : (end / boundingRect.width) * (clip?.metadata?.duration || 0);
              setStartPosition(start);
              setEndPosition(pinEndPosition ? boundingRect.width : end);
            } else {
              durations.start =
                (newEndPosition / boundingRect.width) *
                (clip?.metadata?.duration || 0);
              durations.end = undefined;
              setStartPosition(newEndPosition);
              setEndPosition(null);
            }

            selectionChange(durations);
          }
        }}
        onMouseLeave={(e) => {
          if (isDraggingSelectionBox) {
            setIsDraggingSelectionBox(false);
            return;
          }
          if (!isDragging && !edit.isScrubbing) return;
          const boundingRect = containerRef.current?.getBoundingClientRect();
          if (boundingRect) {
            const cursorX = e.clientX;
            if (edit.isScrubbing) {
              playbar.userSetCurrentProgress(
                ((edit.scrubPosition || 0) /
                  containerRef.current?.getBoundingClientRect().width) *
                  100
              );
              requestAnimationFrame(() => {
                edit.setIsScrubbing(false);
              });
              return;
            }
            if (
              edit.selectionRange &&
              maxSelectionRangeSecs &&
              edit.selectionRange.end - edit.selectionRange.start ===
                maxSelectionRangeSecs
            )
              return;

            if (cursorX < boundingRect.left) {
              requestAnimationFrame(() => {
                setStartPosition(0);
                selectionChange({
                  start: 0,
                  end: edit.selectionRange?.end,
                });
              });
            } else if (cursorX > boundingRect.right) {
              requestAnimationFrame(() => {
                setEndPosition(boundingRect.width);
                selectionChange({
                  start: edit.selectionRange?.start,
                  end: clip?.metadata?.duration,
                });
              });
            }
            setIsDraggingSelectionBox(false);
            setIsDragging(false);
            edit.setIsScrubbing(false);
            setActiveDragHandle(null);
            if (
              startPosition !== null &&
              endPosition !== null &&
              Math.abs(endPosition - startPosition) < MIN_SELECTION_WIDTH
            ) {
              edit.clearSelectionRange();
            }
          }
        }}
        onMouseUp={() => {
          if (isDraggingSelectionBox) {
            setIsDraggingSelectionBox(false);
            return;
          }
          setIsDragging(false);
          //setActiveDragHandle(null);
          // This is specific to Trim mode, in other modes a single point will be selectable

          if (
            edit.scrubPosition !== null ||
            (startPosition !== null &&
              (endPosition === null || isNaN(endPosition))) ||
            (startPosition !== null &&
              endPosition !== null &&
              endPosition - startPosition < 0.1)
          ) {
            if (!edit.isScrubbing) {
              edit.clearSelectionRange();
              edit.setIsScrubbing(true);
            }

            requestAnimationFrame(() => {
              if (clip.id !== playbar.clip?.id) {
                playbar.playClip(
                  clip,
                  null,
                  null,
                  true,
                  ((edit.scrubPosition || startPosition || 0) /
                    containerRef.current?.getBoundingClientRect().width) *
                    (clip?.metadata?.duration || 0)
                );
              } else {
                playbar.userSetCurrentProgress(
                  ((edit.scrubPosition || startPosition || 0) /
                    containerRef.current?.getBoundingClientRect().width) *
                    100
                );
              }
              requestAnimationFrame(() => {
                edit.setIsScrubbing(false);
              });
            });
            return;
          } else if (
            startPosition !== null &&
            endPosition !== null &&
            Math.abs(endPosition - startPosition) < MIN_SELECTION_WIDTH
          ) {
            edit.clearSelectionRange();
          }
          edit.setIsScrubbing(false);
        }}
        onMouseOut={() => {}}
        onBlur={() => {}}
      >
        <div className='relative' ref={containerRef}>
          {(!clipSamples.length ||
            (clip?.id && clips.pendingAlignedLyricsClipIds.has(clip?.id))) && (
            <div className='absolute top-0 flex h-full w-full flex-row items-center justify-center'>
              <SpinnerSVG />
            </div>
          )}
          <div
            className='absolute'
            style={{
              backgroundColor: isEditModeEnabled
                ? 'rgba(199, 61, 102, 0.4)'
                : 'rgba(255,255,255,0.1)',
              height: `${HEIGHT_PIXELS * SCALE_HEIGHT}px`,
              top: `${selectionBoxTopOffset}px`,
              display: startPosition !== null ? 'block' : 'none',
              left: startPosition ? `${startPosition}px` : undefined,
              width:
                endPosition !== null &&
                startPosition !== null &&
                !!clip.metadata?.duration
                  ? `${endPosition - startPosition}px`
                  : startPosition !== null
                    ? '1px'
                    : 0,
              cursor: isDraggingSelectionBox
                ? 'grabbing'
                : isShiftPressed
                  ? 'grab'
                  : 'pointer',
              pointerEvents:
                startPosition !== null &&
                endPosition !== null &&
                !isDragging &&
                !edit.isScrubbing
                  ? undefined
                  : 'none',
              zIndex: PLAYBAR_Z_INDEX,
            }}
            onMouseDown={(e: any) => {
              if (pinEndPosition) {
                return;
              }
              if (e.shiftKey) {
                setIsDraggingSelectionBox(true);
                edit.setSelectionBoxDragStart(e.clientX);
                edit.setSelectionBoxPositionStart({
                  startPosition: startPosition || 0,
                  endPosition: endPosition || 0,
                });
                return;
              }
              edit.setIsScrubbing(true);
              requestAnimationFrame(() => {
                const boundingRect =
                  containerRef.current?.getBoundingClientRect();
                const position = e.clientX - boundingRect.x;
                playbar.userSetCurrentProgress(
                  (position / boundingRect.width) * 100
                );
              });
            }}
            onMouseMove={(e: any) => {
              if (isDraggingSelectionBox) {
                handleMoveSelectionBox(e);
              }
            }}
            onMouseUp={() => {
              setIsDraggingSelectionBox(false);
              edit.setSelectionBoxDragStart(null);
              edit.setSelectionBoxPositionStart(null);
            }}
          >
            {startPosition !== null &&
            endPosition !== null &&
            (Math.abs(endPosition - startPosition) > MIN_SELECTION_WIDTH ||
              pinEndPosition) ? (
              <>
                {isEditModeEnabled ? (
                  <>
                    <div
                      onMouseDown={(e) => {
                        setIsDragging(true);
                        setActiveDragHandle('l');
                        e.stopPropagation();
                      }}
                      className={`bg-transparent ${activeDragHandle === 'l' ? 'brightness-150' : ''} absolute left-0 h-full w-2 cursor-ew-resize content-center items-center border-l-2 border-accent-pink hover:brightness-150 active:cursor-ew-resize`}
                    >
                      <svg
                        xmlns='http://www.w3.org/2000/svg'
                        viewBox='0 0 512 512'
                        className='absolute bottom-0 left-0 h-3 w-3'
                        style={{ marginBottom: '-10px', marginLeft: '-7px' }}
                      >
                        <path d='M0 480L256 32 512 480H0z' fill='#C73D66' />
                      </svg>
                      <svg
                        xmlns='http://www.w3.org/2000/svg'
                        viewBox='0 0 512 512'
                        className='absolute top-0 left-0 h-3 w-3 rotate-180'
                        style={{ marginTop: '-10px', marginLeft: '-7px' }}
                      >
                        <path d='M0 480L256 32 512 480H0z' fill='#C73D66' />
                      </svg>
                    </div>
                    {pinEndPosition ? null : (
                      <div
                        onMouseDown={(e) => {
                          setIsDragging(true);
                          setActiveDragHandle('r');
                          e.stopPropagation();
                        }}
                        className={`bg-transparent ${activeDragHandle === 'r' ? 'brightness-150' : ''} absolute right-0 h-full w-2 cursor-ew-resize content-center items-center border-r-2 border-accent-pink hover:brightness-150 active:cursor-ew-resize`}
                      >
                        <svg
                          xmlns='http://www.w3.org/2000/svg'
                          viewBox='0 0 512 512'
                          className='absolute right-0 bottom-0 h-3 w-3'
                          style={{ marginBottom: '-10px', marginRight: '-7px' }}
                        >
                          <path d='M0 480L256 32 512 480H0z' fill='#C73D66' />
                        </svg>
                        <svg
                          xmlns='http://www.w3.org/2000/svg'
                          viewBox='0 0 512 512'
                          className='absolute top-0 right-0 h-3 w-3 rotate-180'
                          style={{ marginTop: '-10px', marginRight: '-7px' }}
                        >
                          <path d='M0 480L256 32 512 480H0z' fill='#C73D66' />
                        </svg>
                      </div>
                    )}
                  </>
                ) : (
                  <>
                    <div
                      onMouseDown={(e) => {
                        setIsDragging(true);
                        setActiveDragHandle('l');
                        e.stopPropagation();
                      }}
                      className={`${activeDragHandle === 'l' ? 'bg-white' : 'bg-neutral-400'} absolute left-0 h-full w-1 cursor-ew-resize content-center items-center rounded-lg hover:bg-white`}
                    />
                    {pinEndPosition ? null : (
                      <div
                        onMouseDown={(e) => {
                          setIsDragging(true);
                          setActiveDragHandle('r');
                          e.stopPropagation();
                        }}
                        className={`${activeDragHandle === 'r' ? 'bg-white' : 'bg-neutral-400'} absolute right-0 h-full w-1 cursor-ew-resize content-center items-center rounded-lg hover:bg-white`}
                      />
                    )}
                  </>
                )}

                {showTimestamps ? (
                  <>
                    <div
                      draggable={false}
                      className={`w-min-content pointer-events-none absolute bottom-0 left-0 h-auto rounded-sm bg-background-primary/70 px-1 font-mono text-[8px] font-bold text-foreground-primary backdrop-blur-md transition-opacity duration-525 select-none`}
                    >
                      {encodeTimeFormat(
                        Math.max(edit.selectionRange?.start || 0, 0),
                        1
                      )}
                    </div>
                    <div
                      draggable={false}
                      className={`w-min-content pointer-events-none absolute right-0 bottom-0 h-auto rounded-sm bg-background-primary/70 px-1 font-mono text-[8px] font-bold text-foreground-primary backdrop-blur-md transition-opacity duration-525 select-none`}
                    >
                      {encodeTimeFormat(edit.selectionRange?.end, 1)}
                    </div>
                  </>
                ) : null}
                {!!actionButtonText &&
                !!onActionButtonClick &&
                edit.checkActionButtonVisibility() ? (
                  <div
                    className={`absolute left-2 flex h-full w-[calc(100%-16px)] flex-row ${containerRef.current.getBoundingClientRect().width - startPosition < 40 ? 'justify-end' : endPosition < 40 ? 'justify-start' : 'justify-center'} items-center`}
                  >
                    <div
                      className='z-1000 h-auto w-auto'
                      onMouseDown={(e) => e.stopPropagation()}
                    >
                      <Button
                        shape={ButtonShape.Pill}
                        icon={
                          <CheckIcon className='h-4 w-4 fill-primary stroke-primary group-hover:fill-dumbo-50 group-hover:stroke-dumbo-50' />
                        }
                        onClick={(e: any): any => {
                          e.stopPropagation();
                          onActionButtonClick();
                        }}
                      />
                    </div>
                  </div>
                ) : null}
              </>
            ) : null}
          </div>
          {playbar.currentTime &&
          playbar.clip?.id === clip?.id &&
          containerRef.current ? (
            <div
              className={`pointer-events-none absolute h-full w-[0px] border border-accent-brand ${!edit.isScrubbing && !isDraggingPlaybar ? 'transition transition-[left] duration-525 ease-linear' : ''}`}
              style={{
                left: `${edit.isScrubbing && edit.scrubPosition !== null ? edit.scrubPosition : (playbar.currentTime / playbar.duration) * containerRef.current.getBoundingClientRect().width}px`,
              }}
            ></div>
          ) : null}
          {clip?.id && clips.pendingAlignedLyricsClipIds.has(clip?.id) ? (
            <div style={{ width: '100%', height: `${HEIGHT_PIXELS}px` }}></div>
          ) : null}
          <div
            className={`cursor-pointer ${clip?.id && clips.pendingAlignedLyricsClipIds.has(clip?.id) ? 'hidden' : ''}`}
            onMouseDown={(e: any) => {
              const boundingRect = e.target.getBoundingClientRect();
              const newStart = e.clientX - boundingRect.x;
              /*if (!selectionType) {
              edit.setScrubPosition(newStart);
              edit.setIsScrubbing(true);
              return;
            }*/
              if (
                !selectionType ||
                (startPosition !== null &&
                  endPosition !== null &&
                  !isNaN(startPosition) &&
                  !isNaN(endPosition))
              ) {
                edit.setIsScrubbing(true);
                requestAnimationFrame(() => {
                  if (clip?.id !== playbar.clip?.id) {
                    playbar.playClip(
                      clip,
                      null,
                      null,
                      true,
                      (newStart / boundingRect.width) *
                        (clip?.metadata?.duration || 0)
                    );
                  } else {
                    playbar.userSetCurrentProgress(
                      (newStart / boundingRect.width) * 100
                    );
                  }
                });
                return;
              }
              if (pinEndPosition) {
                setStartPosition(newStart);
                setInputStartPosition(newStart);
                setEndPosition(boundingRect.width);
                setIsDragging(true);
                setActiveDragHandle(null);
                selectionChange({
                  start:
                    (newStart / boundingRect.width) *
                    (clip?.metadata?.duration || 0),
                  end: clip?.metadata?.duration,
                });
              } else {
                setEndPosition(null);
                setStartPosition(newStart);
                setInputStartPosition(newStart);
                setIsDragging(true);
                setActiveDragHandle(null);
                selectionChange({
                  start:
                    (newStart / boundingRect.width) *
                    (clip?.metadata?.duration || 0),
                  end: undefined,
                });
              }
            }}
          >
            <svg
              ref={svgRef}
              style={{
                width: '100%',
                height: `${HEIGHT_PIXELS}px`,
                paddingLeft: '0px',
                paddingRight: '0px',
              }}
              id={`demo${index || ''}`}
            ></svg>
          </div>
          {startPosition !== null &&
          endPosition !== null &&
          (!isEditModeEnabled || edit.activeEditTool === 'extend') ? (
            <>
              {isEditModeEnabled ? null : (
                <div
                  className='pointer-events-none absolute top-0 left-0 z-2 h-full bg-background-secondary opacity-70 select-none'
                  style={{
                    width: startPosition
                      ? `${Math.max(startPosition, 0)}px`
                      : '0px',
                  }}
                ></div>
              )}
              <div
                className='pointer-events-none absolute top-0 right-0 z-2 h-full bg-background-secondary opacity-70 select-none'
                style={{
                  width:
                    isEditModeEnabled && edit.activeEditTool === 'extend'
                      ? startPosition && containerRef.current
                        ? `${Math.max(containerRef.current?.getBoundingClientRect().width - startPosition, 0)}px`
                        : '0px'
                      : endPosition && containerRef.current
                        ? `${Math.max(containerRef.current?.getBoundingClientRect().width - endPosition, 0)}px`
                        : '0px',
                }}
              ></div>
            </>
          ) : null}
        </div>
      </div>
    );
  }
);

export default D3Waveform;
