import { WebApplication } from '@/Application/WebApplication'
import { getBase64FromBlob } from '@/Utils'
import { FileItem, classNames } from '@standardnotes/snjs'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react'
import Button from '../Button/Button'
import { createObjectURLWithRef } from './CreateObjectURLWithRef'
import ImagePreview from './ImagePreview'
import { OptionalSuperEmbeddedImageProps } from './OptionalSuperEmbeddedImageProps'
import { PreviewableTextFileTypes, RequiresNativeFilePreview } from './isFilePreviewable'
import TextPreview from './TextPreview'
import { parseFileName, sanitizeFileName } from '@standardnotes/utils'
import VideoPreview from './VideoPreview'

type Props = {
  application: WebApplication
  file: FileItem
  bytes: Uint8Array
  isEmbeddedInSuper: boolean
} & OptionalSuperEmbeddedImageProps

const PreviewComponent: FunctionComponent<Props> = ({
  application,
  file,
  bytes,
  isEmbeddedInSuper,
  imageZoomLevel,
  setImageZoomLevel,
  alignment,
  changeAlignment,
}) => {
  const objectUrlRef = useRef<string>()

  const objectUrl = useMemo(() => {
    return createObjectURLWithRef(file.mimeType, bytes, objectUrlRef)
  }, [bytes, file.mimeType])

  useEffect(() => {
    const objectUrl = objectUrlRef.current

    return () => {
      if (objectUrl) {
        URL.revokeObjectURL(objectUrl)
        objectUrlRef.current = ''
      }
    }
  }, [])

  const isNativeMobileWeb = application.isNativeMobileWeb()
  const requiresNativePreview = RequiresNativeFilePreview.includes(file.mimeType)

  const openNativeFilePreview = useCallback(async () => {
    if (!isNativeMobileWeb) {
      throw new Error('Native file preview cannot be used on non-native platform')
    }

    const fileBase64 = await getBase64FromBlob(
      new Blob([bytes], {
        type: file.mimeType,
      }),
    )

    const { name, ext } = parseFileName(file.name)
    const sanitizedName = sanitizeFileName(name)
    const filename = `${sanitizedName}.${ext}`

    void application.mobileDevice.previewFile(fileBase64, filename)
  }, [application, bytes, file.mimeType, file.name, isNativeMobileWeb])

  if (isNativeMobileWeb && requiresNativePreview) {
    return (
      <div className="flex flex-grow flex-col items-center justify-center">
        <div className="max-w-[30ch] text-center text-base font-bold">
          This file can only be previewed in an external app
        </div>
        <Button className="mt-3" primary onClick={openNativeFilePreview}>
          Open file preview
        </Button>
      </div>
    )
  }

  if (file.mimeType.startsWith('image/')) {
    return (
      <ImagePreview
        objectUrl={objectUrl}
        isEmbeddedInSuper={isEmbeddedInSuper}
        imageZoomLevel={imageZoomLevel}
        setImageZoomLevel={setImageZoomLevel}
        alignment={alignment}
        changeAlignment={changeAlignment}
      />
    )
  }

  if (file.mimeType.startsWith('video/')) {
    return (
      <VideoPreview
        file={file}
        filesController={application.filesController}
        objectUrl={objectUrl}
        isEmbeddedInSuper={isEmbeddedInSuper}
      />
    )
  }

  if (file.mimeType.startsWith('audio/')) {
    return (
      <div className="flex h-full w-full items-center justify-center">
        <audio src={objectUrl} controls />
      </div>
    )
  }

  if (PreviewableTextFileTypes.includes(file.mimeType)) {
    return <TextPreview bytes={bytes} />
  }

  const isPDF = file.mimeType === 'application/pdf'

  return (
    <object
      className={classNames('h-full w-full', isPDF && 'min-h-[65vh]')}
      data={isPDF ? objectUrl + '#view=FitV' : objectUrl}
    />
  )
}

export default PreviewComponent
