import { AnchorButton, Button, ButtonGroup, Divider } from '@blueprintjs/core'
import { css } from '@emotion/react'
import { lazy, Suspense, useMemo, type FC } from 'react'
import CenteredSpinner from '../CenteredSpinner'
import Container from '../Container'
import ErrorMessage from '../ErrorMessage'
import Header from './Header'
import type { Document, RendererProps } from './types'

const ImageRenderer = lazy(() => import('./renderers/ImageRenderer'))
const NotSupportedRenderer = lazy(
  () => import('./renderers/NotSupportedRenderer')
)
const PDFRenderer = lazy(() => import('./renderers/PDFRenderer'))
const TextRenderer = lazy(() => import('./renderers/TextRenderer'))
const VideoRenderer = lazy(() => import('./renderers/VideoRenderer'))

const SUPPORTED_FILE_TYPES: {
  [name: string]: FC<RendererProps>
} = {
  // image: most common formats as listed at https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Containers#browser_compatibility
  apng: ImageRenderer, // not tested: no sample file found
  png: ImageRenderer,
  avif: ImageRenderer,
  gif: ImageRenderer,
  jpg: ImageRenderer,
  jpeg: ImageRenderer,
  jpe: ImageRenderer,
  jif: ImageRenderer, // not tested: no sample file found
  jfif: ImageRenderer,
  svg: ImageRenderer, // requires Content-Type to be image/svg+xml
  webp: ImageRenderer,

  // audio and video: most common formats as listed at https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Containers#browser_compatibility
  '3gp': VideoRenderer, // audio and video
  aac: VideoRenderer, // audio
  flac: VideoRenderer, // audio
  mpg: VideoRenderer, // audio and video
  mpeg: VideoRenderer, // audio and video
  mp3: VideoRenderer, // audio
  mp4: VideoRenderer, // audio and video
  m4a: VideoRenderer, // audio
  m4v: VideoRenderer, // video
  m4p: VideoRenderer, // video
  oga: VideoRenderer, // audio
  ogg: VideoRenderer, // audio and video
  ogv: VideoRenderer, // video
  mov: VideoRenderer, // video
  wav: VideoRenderer, // audio
  webm: VideoRenderer, // audio and video

  // documents
  pdf: PDFRenderer,
  txt: TextRenderer,
}
export const SUPPORTED_FILE_EXTENSIONS = Object.keys(SUPPORTED_FILE_TYPES)

interface DocViewerProps {
  doc: Document
  loading?: boolean
  error?: Error
  contentOnly?: boolean
  onBack?: () => void
}

const grid = css`
  display: grid;
  grid-template-rows: 2rem 1fr;
  padding: 0.5rem;
  grid-gap: 1rem;
  height: 100vh;
`

const fileView = css`
  overflow-y: auto;
  display: flex;
  flex-direction: column;
`

const contentClass = css`
  flex: 1;
  overflow-y: auto;
`

const DocViewerPage: FC<DocViewerProps> = ({
  doc,
  loading,
  error,
  contentOnly,
  onBack,
}) => {
  const extension = useMemo(() => doc.fileName.split('.').pop(), [doc.fileName])

  const content = useMemo(() => {
    if (loading) {
      return <CenteredSpinner />
    }
    if (error) {
      return (
        <ErrorMessage>
          <h1>Error occurred!</h1>
          <p>{error.message}</p>
        </ErrorMessage>
      )
    }
    if (!extension || !SUPPORTED_FILE_EXTENSIONS.includes(extension)) {
      return <NotSupportedRenderer doc={doc} />
    }

    const Renderer = SUPPORTED_FILE_TYPES[extension]
    return <Renderer doc={doc} />
  }, [doc, error, extension, loading])

  if (contentOnly) {
    return content
  }

  return (
    <div css={grid}>
      <div>
        <ButtonGroup minimal>
          {onBack && (
            <>
              <Button intent='primary' icon='arrow-left' onClick={onBack}>
                Back
              </Button>
              <Divider />
            </>
          )}
          <AnchorButton
            icon='import'
            href={doc.uri}
            target='_blank'
            rel='noreferrer'
            loading={loading}
            download={doc.fileName}
          >
            Download
          </AnchorButton>
        </ButtonGroup>
      </div>

      <Container css={fileView}>
        <Header fileName={doc.fileName} />
        <Suspense fallback={<CenteredSpinner />}>
          <div css={contentClass}>{content}</div>
        </Suspense>
      </Container>
    </div>
  )
}

export default DocViewerPage
