"use client"

import { useEffect, useRef, useState } from "react"
import { useQueryClient } from "@tanstack/react-query"
import { Play } from "lucide-react"
import type { DriveFileInfo } from "@/lib/api/types"
import { useDrivePreviewThumb } from "@/lib/api/hooks/use-drive-preview-thumb"
import {
  usePublicSharePreviewThumb,
  type PublicShareThumbContext,
} from "@/lib/api/hooks/use-public-share-preview-thumb"
import { DriveFileTypeIcon } from "@/lib/drive/drive-file-icon"
import {
  drivePreviewKind,
  driveServerThumbnail,
  isOfficeFormat,
} from "@/lib/drive/drive-preview"
import { cn } from "@/lib/utils"

function useInView(rootMargin = "200px") {
  const ref = useRef<HTMLDivElement>(null)
  const [inView, setInView] = useState(false)

  useEffect(() => {
    const el = ref.current
    if (!el) return

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry?.isIntersecting) {
          setInView(true)
          observer.disconnect()
        }
      },
      { rootMargin }
    )

    observer.observe(el)
    return () => observer.disconnect()
  }, [rootMargin])

  return { ref, inView }
}

function PreviewContent({
  url,
  display,
  darkInvert,
  onError,
}: {
  url: string
  display: "image" | "video"
  darkInvert?: boolean
  onError: () => void
}) {
  if (display === "video") {
    return (
      <>
        <video
          src={url}
          muted
          playsInline
          preload="metadata"
          className="h-full w-full object-cover"
          onLoadedData={(e) => {
            const v = e.currentTarget
            if (v.currentTime === 0) v.currentTime = 0.1
          }}
          onError={onError}
        />
        <div
          className="pointer-events-none absolute inset-0 flex items-center justify-center bg-black/20"
          aria-hidden
        >
          <div className="flex h-9 w-9 items-center justify-center rounded-full bg-black/55 shadow-md">
            <Play className="ml-0.5 h-4 w-4 fill-white text-white" />
          </div>
        </div>
      </>
    )
  }

  return (
    <img
      src={url}
      alt=""
      className={cn(
        "h-full w-full object-cover",
        darkInvert && "dark:invert dark:hue-rotate-180",
      )}
      draggable={false}
      onError={onError}
    />
  )
}

export function FileThumbnail({
  file,
  variant = "grid",
  inSharedView,
  publicShare,
  className,
}: {
  file: DriveFileInfo
  variant?: "list" | "grid"
  inSharedView?: boolean
  publicShare?: PublicShareThumbContext
  className?: string
}) {
  const { ref, inView } = useInView()
  const [failed, setFailed] = useState(false)
  const retriedRef = useRef(false)
  const queryClient = useQueryClient()
  const previewKind = drivePreviewKind(file)
  const canPreview =
    file.type === "file" &&
    previewKind !== "audio" &&
    (driveServerThumbnail(file) || previewKind !== null)
  const showPreview = canPreview && !failed
  const authThumb = useDrivePreviewThumb(file, !publicShare && inView && showPreview)
  const publicThumb = usePublicSharePreviewThumb(file, publicShare, inView && showPreview)
  const { data, isLoading } = publicShare ? publicThumb : authThumb

  const showIcon = !showPreview || failed || (!data && !isLoading)
  const darkInvertThumb = isOfficeFormat(file)
  const iconSize = variant === "list" ? "md" : "lg"
  const sizeClass =
    variant === "list" ? "h-10 w-10 rounded-lg" : "aspect-[4/3] w-full rounded-lg"

  useEffect(() => {
    retriedRef.current = false
    setFailed(false)
  }, [file.path, file.etag])

  const handlePreviewError = () => {
    if (!retriedRef.current && data?.url.startsWith("blob:")) {
      retriedRef.current = true
      void queryClient.invalidateQueries({
        queryKey: publicShare
          ? ["public-share", "preview-thumb", publicShare.token, file.path, file.etag]
          : ["drive", "preview-thumb", file.path, file.etag],
      })
      return
    }
    setFailed(true)
  }

  return (
    <div
      ref={ref}
      className={cn(
        "relative shrink-0 overflow-hidden bg-[#f8f9fa] dark:bg-muted/30",
        sizeClass,
        className
      )}
    >
      {showIcon ? (
        <div className="flex h-full w-full items-center justify-center">
          <DriveFileTypeIcon
            file={file}
            inSharedView={inSharedView}
            size={iconSize}
            className={isLoading && showPreview ? "opacity-40" : undefined}
          />
        </div>
      ) : null}

      {showPreview && isLoading ? (
        <div className="absolute inset-0 animate-pulse bg-muted" aria-hidden />
      ) : null}

      {showPreview && data ? (
        <div className="absolute inset-0 overflow-hidden bg-white dark:bg-transparent">
          <PreviewContent
            url={data.url}
            display={data.display}
            darkInvert={darkInvertThumb}
            onError={handlePreviewError}
          />
        </div>
      ) : null}
    </div>
  )
}
