import type { ResultOf, VariablesOf } from '@inject/graphql/graphql'
import { GetFileInfo } from '@inject/graphql/queries'
import CenteredSpinner from '@inject/shared/components/CenteredSpinner'
import { useCallback, useEffect, useState, type FC } from 'react'
import { useClient } from 'urql'

interface RenderedContentProps {
  renderedContent: string
  teamId: string
  inInstructor: boolean
  className?: string
}

// TODO: use response header Content-Disposition (value: `attachment; filename="website-root.jpg"`) instead of fetching file infos
const RenderedContent: FC<RenderedContentProps> = ({
  renderedContent,
  teamId,
  inInstructor,
  className,
}) => {
  const client = useClient()
  const getFileInfo = useCallback(
    (fileInfoId: string) =>
      client.query<
        ResultOf<typeof GetFileInfo>,
        VariablesOf<typeof GetFileInfo>
      >(GetFileInfo, { fileInfoId }),
    [client]
  )

  const [processedContent, setProcessedContent] = useState(renderedContent)
  const [loading, setLoading] = useState(false)
  useEffect(() => {
    const processContent = async () => {
      try {
        setLoading(true)
        // Find all file IDs
        const regex = /<embed[^>]*file_info_id="([^"]*)"[^>]*>/g
        const matches = [...renderedContent.matchAll(regex)]

        // Fetch all file info concurrently
        const fileInfos = await Promise.all(
          matches.map(async ([match, fileInfoId]) => {
            const { data } = await getFileInfo(fileInfoId)
            return {
              match,
              fileInfoId,
              fileName: data?.fileInfo?.fileName || '',
            }
          })
        )

        // Replace all matches with doc-viewer elements
        let result = renderedContent
        fileInfos.forEach(({ match, fileInfoId, fileName }) => {
          result = result.replace(
            match,
            `<doc-viewer team_id="${teamId}" file_info_id="${fileInfoId}" in_instructor="${inInstructor}" file_name="${fileName}"></doc-viewer>`
          )
        })

        setProcessedContent(result)
      } catch (error) {
        console.error('Error processing content:', error)
      } finally {
        setLoading(false)
      }
    }

    processContent()
  }, [renderedContent, teamId, inInstructor, getFileInfo])

  if (loading) {
    return <CenteredSpinner />
  }

  return (
    <div
      className={className}
      dangerouslySetInnerHTML={{
        __html: processedContent,
      }}
    />
  )
}

export default RenderedContent
