import * as React from 'react';
import {augmentVideoFile, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize, formatNumeral, formatSecondsDurationConcise} from '@/utils/numeral';
import {useAugmentedFile, useMediaControls} from '@tesseract-design/web-blob-react';
import clsx from 'clsx';

type VideoFilePreviewDerivedComponent = HTMLVideoElement;

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

export const VideoFilePreview = React.forwardRef<VideoFilePreviewDerivedComponent, VideoFilePreviewProps>(({
  file,
  className,
  style,
  disabled = false,
  enhanced = false,
  ...etcProps
}, forwardedRef) => {
  const { augmentedFile, error } = useAugmentedFile({
    file,
    augmentFunction: augmentVideoFile,
  });
  const {
    seekRef,
    volumeRef,
    isPlaying,
    adjustVolume,
    reset,
    startSeek,
    endSeek,
    setSeek,
    updateSeekFromPlayback,
    refreshControls,
    durationDisplay = 0,
    currentTimeDisplay = 0,
    seekTimeDisplay = 0,
    isSeeking,
    isSeekTimeCountingDown,
    mediaControllerRef,
    handleAction,
    filenameRef,
  } = useMediaControls<HTMLVideoElement>({
    controllerRef: forwardedRef,
  });
  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">
              <video
                {...etcProps}
                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}
                onLoadedMetadata={refreshControls}
                onDurationChange={refreshControls}
                onEnded={reset}
                onTimeUpdate={updateSeekFromPlayback}
                data-testid="preview"
                controls={!enhanced}
              >
                <source
                  src={augmentedFile.metadata.previewUrl}
                  type={augmentedFile.type}
                />
              </video>
              </div>
              {enhanced && (
                <div className="w-full flex-shrink-0 h-10 flex gap-4">
                  <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 font-bold">
            <dt className="sr-only">
              Name
            </dt>
            <dd
              className="m-0 w-full text-ellipsis overflow-hidden"
              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?.width === 'number'
            && typeof augmentedFile.metadata?.height === 'number'
            && (
              <div>
                <dt className="sr-only">
                  Pixel Dimensions
                </dt>
                <dd
                  className="m-0 w-full text-ellipsis overflow-hidden"
                >
                  {formatNumeral(augmentedFile.metadata.width)}&times;{formatNumeral(augmentedFile.metadata.height)} pixels
                </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>
  );
});

VideoFilePreview.displayName = 'VideoFilePreview';
