import * as React from 'react';
import {WaveSurferOptions} from 'wavesurfer.js';
import clsx from 'clsx';
import {getFormValues} from '@theoryofnekomata/formxtra';

type WaveformCanvasDerivedElement = HTMLDivElement;

export interface WaveformCanvasProps
  extends React.HTMLProps<WaveformCanvasDerivedElement>,
    Omit<WaveSurferOptions, 'plugins' | 'height' | 'media' | 'container' | 'fillParent' | 'url' | 'autoplay' | 'renderFunction'> {
  audioRef?: React.Ref<HTMLAudioElement>;
}

export const WaveformCanvas = React.forwardRef<WaveformCanvasDerivedElement, WaveformCanvasProps>(({
  className,
  children,
  controls,
  waveColor,
  progressColor,
  cursorColor,
  cursorWidth,
  barWidth,
  barGap,
  barRadius,
  barHeight,
  barAlign,
  minPxPerSec,
  peaks,
  duration,
  autoPlay,
  interact,
  hideScrollbar,
  audioRate,
  autoScroll,
  autoCenter,
  sampleRate,
  splitChannels,
  normalize,
  audioRef,
  ...etcProps
}, forwardedRef) => {
  const [isPlaying, setIsPlaying] = React.useState(false);
  const defaultRef = React.useRef<WaveformCanvasDerivedElement>(null);
  const containerRef = forwardedRef ?? defaultRef;
  const waveSurferRef = React.useRef<any>(null);

  const handleAction: React.FormEventHandler<HTMLFormElement> = (e) => {
    e.preventDefault();
    const nativeEvent = e.nativeEvent as unknown as { submitter: HTMLElement };
    const formData = getFormValues(
      e.currentTarget,
      {
        submitter: nativeEvent.submitter,
      }
    );
    const actionName = formData['action'] as string;
    switch (actionName) {
    case 'togglePlayback':
      setIsPlaying((prev) => !prev);
      break;
    default:
      break;
    }
  };

  React.useEffect(() => {
    if (!(typeof audioRef === 'object' && audioRef)) {
      return;
    }
    const { current: media } = audioRef;
    if (!media) {
      return;
    }

    if (!(typeof containerRef === 'object' && containerRef)) {
      return;
    }
    const { current: container } = containerRef;
    if (!container) {
      return;
    }

    const load = async (media: HTMLAudioElement, container: HTMLElement) => {
      const {default: WaveSurfer} = await import('wavesurfer.js');
      const waveSurferInstance = WaveSurfer.create({
        container,
        height: 'auto',
        autoplay: autoPlay,
        fillParent: true,
        waveColor,
        progressColor,
        cursorColor,
        barWidth,
        barGap,
        barRadius,
        barHeight,
        barAlign,
        minPxPerSec,
        peaks,
        duration,
        interact,
        hideScrollbar,
        audioRate,
        autoScroll,
        autoCenter,
        sampleRate,
        splitChannels,
        normalize,
        cursorWidth,
        plugins: [],
        media,
      });
      waveSurferInstance.on('ready', () => {
        if (!container) {
          return;
        }
        while (container.children.length > 1) {
          container.removeChild(container.children[0]);
        }
      });
      await waveSurferInstance.load(media.currentSrc);
      waveSurferInstance.setTime(media.currentTime);
      return waveSurferInstance;
    };

    const { current: waveSurferCurrent } = waveSurferRef;
    load(media, container)
      .then((i) => {
        waveSurferRef.current = i;
      })
      .catch((error) => {
        console.log(error);
      });

    return () => {
      if (waveSurferCurrent) {
        (waveSurferCurrent as unknown as Record<string, Function>).destroy();
      }
      if (container) {
        container.innerHTML = '';
      }
    };
  }, [
    audioRef,
    autoPlay,
    waveColor,
    progressColor,
    cursorColor,
    barWidth,
    barGap,
    barRadius,
    barHeight,
    barAlign,
    minPxPerSec,
    peaks,
    duration,
    interact,
    hideScrollbar,
    audioRate,
    autoScroll,
    autoCenter,
    sampleRate,
    splitChannels,
    normalize,
    cursorWidth,
    containerRef,
  ]);

  return (
    <div
      className={clsx(
        'flex flex-col',
        className,
      )}
    >
      <div
        className="flex-auto relative aspect-video sm:aspect-auto"
      >
        <div className="absolute top-0 left-0 w-full h-full">
          <div className="w-full h-full relative"
            ref={containerRef}
          />
        </div>
      </div>
      {controls && (
        <form
          onSubmit={handleAction}
        >
          <button
            type="submit"
            name="action"
            value="togglePlayback"
          >
            {isPlaying ? '⏸' : '▶'}
          </button>
        </form>
      )}
    </div>
  );
});

WaveformCanvas.displayName = 'WavesurferCanvas';
