import * as React from 'react';

export interface UseAudioControlsOptions {
  actionFormKey?: string;
  forwardedRef?: React.Ref<any>;
}

export const useAudioControls = ({
  forwardedRef,
  actionFormKey = 'action' as const,
}: UseAudioControlsOptions) => {
  const mediaControllerRef = React.useRef<HTMLAudioElement>(null);
  const volumeRef = React.useRef<HTMLInputElement>(null);
  const filenameRef = React.useRef<HTMLElement>(null);
  const [isPlaying, setIsPlaying] = React.useState(false);
  const [isSeeking, setIsSeeking] = React.useState(false);
  const [currentTimeDisplay, setCurrentTimeDisplay] = React.useState<number>();
  const [seekTimeDisplay, setSeekTimeDisplay] = React.useState<number>();
  const [durationDisplay, setDurationDisplay] = React.useState<number>();
  const [isSeekTimeCountingDown, setIsSeekTimeCountingDown] = React.useState(false);

  const refreshControls: React.ReactEventHandler<HTMLAudioElement> = React.useCallback((e) => {
    const { currentTarget: mediaController } = e;

    setCurrentTimeDisplay(mediaController.currentTime);
    setDurationDisplay(mediaController.duration);
  }, []);

  const reset: React.ReactEventHandler<HTMLAudioElement> = React.useCallback((e) => {
    const videoElement = e.currentTarget;
    setIsPlaying(false);
    videoElement.currentTime = 0;
  }, []);

  const updateSeekFromPlayback = React.useCallback((e) => {
    if (isSeeking) {
      return;
    }

    const videoElement = e.currentTarget;
    const currentTime = videoElement.currentTime;
    setCurrentTimeDisplay(currentTime);
  }, [isSeeking]);

  const adjustVolume: React.ChangeEventHandler<HTMLInputElement> = React.useCallback((e) => {
    if (!(typeof mediaControllerRef === 'object' && mediaControllerRef !== null)) {
      return;
    }

    if (!mediaControllerRef.current) {
      return;
    }
    const { value } = e.currentTarget;
    mediaControllerRef.current.volume = Number(value);
  }, [mediaControllerRef]);

  const togglePlayback = React.useCallback(() => {
    setIsPlaying((p) => !p);
  }, []);

  const toggleSeekTimeCountMode = React.useCallback(() => {
    setIsSeekTimeCountingDown((b) => !b);
  }, []);

  const download = React.useCallback(() => {
    if (!(typeof mediaControllerRef === 'object' && mediaControllerRef?.current !== null)) {
      return;
    }

    if (!(typeof filenameRef === 'object' && filenameRef?.current !== null)) {
      return;
    }

    const downloadLink = window.document.createElement('a');
    downloadLink.download = filenameRef.current.textContent ?? 'image';
    downloadLink.href = mediaControllerRef.current.currentSrc;
    downloadLink.addEventListener('click', () => {
      downloadLink.remove();
    });
    downloadLink.click();
  }, [mediaControllerRef, filenameRef]);

  const actions = React.useMemo(() => ({
    togglePlayback,
    toggleSeekTimeCountMode,
    download,
  }), [togglePlayback, toggleSeekTimeCountMode, download]);

  const handleAction: React.FormEventHandler<HTMLFormElement> = React.useCallback((e) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget, (e.nativeEvent as unknown as { submitter: HTMLElement }).submitter);
    const actionName = formData.get(actionFormKey) as keyof typeof actions;
    const { [actionName]: actionFunction } = actions;
    actionFunction?.();
  }, [actions, actionFormKey]);

  React.useEffect(() => {
    if (!(typeof mediaControllerRef === 'object' && mediaControllerRef !== null)) {
      return;
    }

    if (!mediaControllerRef.current) {
      return;
    }

    if (isPlaying) {
      //console.log(mediaControllerRef.current);
      void mediaControllerRef.current.play();
      return
    }

    mediaControllerRef.current.pause();
  }, [isPlaying, mediaControllerRef]);

  return React.useMemo(() => ({
    mediaControllerRef,
    refreshControls,
    reset: reset,
    updateSeekFromPlayback,
    isPlaying,
    isSeeking,
    currentTimeDisplay,
    seekTimeDisplay,
    durationDisplay,
    isSeekTimeCountingDown,
    volumeRef,
    adjustVolume,
    filenameRef,
    handleAction,
  }), [
    mediaControllerRef,
    refreshControls,
    reset,
    updateSeekFromPlayback,
    isPlaying,
    isSeeking,
    currentTimeDisplay,
    seekTimeDisplay,
    durationDisplay,
    isSeekTimeCountingDown,
    volumeRef,
    adjustVolume,
    filenameRef,
    handleAction,
  ]);
};
