import * as React from 'react';
import {augmentAudioFile, getMimeTypeDescription} from '@/utils/blob';
import {
  formatFileSize,
  formatNumeral,
  formatSecondsDurationConcise,
  formatSecondsDurationPrecise,
} from '@/utils/numeral';
import {useMediaControls} from '../../hooks/interactive';
import {useAugmentedFile} from '@/categories/blob/react';

import clsx from 'clsx';
import {WaveSurferCanvas} from '@/packages/react-wavesurfer';

type AudioFilePreviewDerivedComponent = HTMLAudioElement;

export interface AudioFilePreviewProps extends Omit<React.HTMLProps<AudioFilePreviewDerivedComponent>, 'controls'> {
  file?: File;
  disabled?: boolean;
  enhanced?: boolean;
}

export const AudioFilePreview = React.forwardRef<AudioFilePreviewDerivedComponent, AudioFilePreviewProps>(({
  file,
  style,
  className,
  enhanced = false,
  disabled = false,
  ...etcProps
}, forwardedRef) => {
  const { augmentedFile, error } = useAugmentedFile({
    file,
    augmentFunction: augmentAudioFile,
  });
  const {
    mediaControllerRef,
    refreshControls,
    reset,
    updateSeekFromPlayback,
    isPlaying,
    isSeeking,
    currentTimeDisplay = 0,
    seekTimeDisplay = 0,
    durationDisplay = 0,
    isSeekTimeCountingDown,
    adjustVolume,
    volumeRef,
    handleAction,
    filenameRef,
    seekRef,
    startSeek,
    endSeek,
    setSeek,
    visualizationMode,
    handleVisualizationModeChange,
  } = useMediaControls<HTMLAudioElement>({
    controllerRef: forwardedRef,
    visualizationMode: 'waveform',
  });
  const formId = React.useId();

  if (!augmentedFile) {
    return null;
  }

  const finalSeekTimeDisplay = isSeekTimeCountingDown ? (durationDisplay - seekTimeDisplay) : seekTimeDisplay;
  const finalCurrentTimeDisplay = isSeekTimeCountingDown ? (durationDisplay - currentTimeDisplay) : currentTimeDisplay;

  return (
    <div
      className={clsx(
        'flex flex-col sm:grid sm:grid-cols-3 gap-8 w-full',
        className,
      )}
      style={style}
    >
      <div className="h-full relative col-span-2">
        {
          typeof augmentedFile.metadata?.previewUrl === 'string'
          && (
            <div
              className="w-full h-full bg-black flex flex-col items-stretch"
              data-testid="preview"
            >
              <div className="w-full flex-auto relative">
                <audio
                  {...etcProps}
                  controls={!enhanced}
                  ref={mediaControllerRef}
                  onLoadedMetadata={refreshControls}
                  onDurationChange={refreshControls}
                  onEnded={reset}
                  onTimeUpdate={updateSeekFromPlayback}
                >
                  <source
                    src={augmentedFile.metadata.previewUrl}
                    type={augmentedFile.type}
                  />
                </audio>
                {visualizationMode === 'waveform' && (
                  <WaveSurferCanvas
                    className="sm:absolute w-full sm:h-full top-0 left-0 block object-center object-contain flex-auto aspect-video sm:aspect-auto bg-[#000000]"
                    ref={mediaControllerRef}
                    data-testid="preview"
                    barWidth={1}
                    barGap={1}
                    waveColor="rgb(199 138 179)"
                    progressColor="rgb(255 153 0)"
                    interact
                  />
                )}
                <div className="flex gap-4 absolute top-0 right-0 z-[2] px-4">
                  <label
                    className={clsx(
                      'h-12 flex text-primary disabled:text-primary focus:text-secondary active:text-tertiary items-center justify-center leading-none gap-4 select-none',
                      'focus:outline-0',
                      'disabled:opacity-50 disabled:cursor-not-allowed',
                    )}
                  >
                    <input
                      type="radio"
                      name="visualizationMode"
                      value="waveform"
                      className="sr-only"
                      onChange={handleVisualizationModeChange}
                    />
                    <span
                      className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
                    >
                      Waveform
                    </span>
                  </label>
                  <label
                    className={clsx(
                      'h-12 flex text-primary disabled:text-primary focus:text-secondary active:text-tertiary items-center justify-center leading-none gap-4 select-none',
                      'focus:outline-0',
                      'disabled:opacity-50 disabled:cursor-not-allowed',
                    )}
                  >
                    <input
                      type="radio"
                      name="visualizationMode"
                      value="spectrum"
                      className="sr-only"
                      onChange={handleVisualizationModeChange}
                    />
                    <span
                      className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
                    >
                      Spectrum
                    </span>
                  </label>
                </div>
              </div>
              {enhanced && (
                <div className="w-full flex-shrink-0 h-10 flex gap-4 relative">
                  <button
                    className="w-10 h-full flex-shrink-0 text-primary"
                    type="submit"
                    name="action"
                    value="togglePlayback"
                    form={formId}
                  >
                    {isPlaying ? '⏸' : '▶'}
                  </button>
                  <div className="flex-auto w-full flex items-center gap-2 text-sm relative">
                    <button
                      className="absolute overflow-hidden w-12 opacity-0 h-10"
                      title="Toggle Seek Time Count Mode"
                      type="submit"
                      name="action"
                      value="toggleSeekTimeCountMode"
                      form={formId}
                    >
                      Toggle Seek Time Count Mode
                    </button>
                    <span
                      className="before:block before:content-[attr(title)] contents tabular-nums"
                      title={
                        `${
                          isSeekTimeCountingDown ? '−' : '+'
                        }${
                          isSeeking
                            ? formatSecondsDurationConcise(finalSeekTimeDisplay)
                            : formatSecondsDurationConcise(finalCurrentTimeDisplay)
                        }`
                      }
                    >
                      <input
                        type="range"
                        className="flex-auto w-full tabular-nums"
                        ref={seekRef}
                        onMouseDown={startSeek}
                        onMouseUp={endSeek}
                        onChange={setSeek}
                        defaultValue="0"
                        step="any"
                      />
                    </span>
                    <span>
                      {formatSecondsDurationConcise(durationDisplay)}
                    </span>
                  </div>
                  <input
                    type="range"
                    ref={volumeRef}
                    max={1}
                    min={0}
                    onChange={adjustVolume}
                    step="any"
                    className="flex-shrink-0 w-12"
                    defaultValue="1"
                    title="Volume"
                  />
                </div>
              )}
            </div>
          )
        }
      </div>
      <div
        className="flex-shrink-0 m-0 flex flex-col gap-4 justify-between"
      >
        <dl data-testid="infoBox">
          <div className="w-full">
            <dt className="sr-only">
              Name
            </dt>
            <dd
              className="m-0 w-full text-ellipsis overflow-hidden font-bold"
              title={augmentedFile.name}
              ref={filenameRef}
            >
              {augmentedFile.name}
            </dd>
          </div>
          <div className="w-full">
            <dt className="sr-only">
              Type
            </dt>
            <dd
              title={augmentedFile.type}
              className="m-0 w-full text-ellipsis overflow-hidden"
            >
              {getMimeTypeDescription(augmentedFile.type, augmentedFile.name)}
            </dd>
          </div>
          <div className="w-full">
            <dt className="sr-only">
              Size
            </dt>
            <dd
              className="m-0 w-full text-ellipsis overflow-hidden"
              title={`${formatNumeral(augmentedFile.size ?? 0)} bytes`}
            >
              {formatFileSize(augmentedFile.size)}
            </dd>
          </div>
          {
            typeof augmentedFile.metadata?.duration === 'number'
            && (
              <div className="w-full">
                <dt className="sr-only">
                  Duration
                </dt>
                <dd
                  className="m-0 w-full text-ellipsis overflow-hidden"
                  title={`${formatNumeral(augmentedFile.metadata.duration ?? 0)} seconds`}
                >
                  {formatSecondsDurationPrecise(augmentedFile.metadata.duration)}
                </dd>
              </div>
            )
          }
        </dl>
        <form
          id={formId}
          onSubmit={handleAction}
          className="flex gap-4"
        >
          <fieldset
            disabled={disabled || typeof error !== 'undefined'}
            className="contents"
          >
            <legend className="sr-only">
              Controls
            </legend>
            <button
              type="submit"
              name="action"
              value="download"
              className={clsx(
                'h-12 flex bg-negative text-primary disabled:text-primary focus:text-secondary active:text-tertiary items-center justify-center leading-none gap-4 select-none',
                'focus:outline-0',
                'disabled:opacity-50 disabled:cursor-not-allowed',
              )}
            >
              <span
                className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
              >
                Download
              </span>
            </button>
          </fieldset>
        </form>
      </div>
    </div>
  );
});

AudioFilePreview.displayName = 'AudioFilePreview';
