import {
  ActionIcon,
  Alert,
  Box,
  Button,
  Card,
  Container,
  FileInput,
  Flex,
  Group,
  Image,
  Loader,
  Progress,
  ScrollArea,
  SimpleGrid,
  Stack,
  Text,
  Title,
} from "@mantine/core"
import {
  IconAlertCircle,
  IconDownload,
  IconMovie,
  IconPhoto,
} from "@tabler/icons-react"
import { useEffect, useRef, useState } from "react"
import { appendCapped } from "./cap"
import type { WorkerResponse } from "./ffmpeg.worker"
import { getServerImage } from "@/components/label/api/label"

export default function VideoFrameExtractor() {
  const [loaded, setLoaded] = useState(false)
  const [isLoading, setIsLoading] = useState(false)
  const [file, setFile] = useState<File | null>(null)
  const [processing, setProcessing] = useState(false)
  const [progress, setProgress] = useState(0)
  const [message, setMessage] = useState("Wait for loading...")
  const [error, setError] = useState<string | null>(null)
  const [images, setImages] = useState<{ url: string; name: string }[]>([])
  const [logs, setLogs] = useState<string[]>([])

  const workerRef = useRef<Worker | null>(null)
  const messageRef = useRef<HTMLDivElement>(null)
  const extractedCountRef = useRef(0)

  const MAX_LOG_LINES = 300
  const MAX_IMAGES = 1500

  // Initialize Worker once
  useEffect(() => {
    queueMicrotask(() => {
      if (!workerRef.current) {
        setIsLoading(true)

        const baseURL = window.location.origin + "/wasm"

        const createWorker = () => {
          const worker = new Worker(
            new URL("./ffmpeg.worker.ts", import.meta.url)
          )
          workerRef.current = worker
          return worker
        }

        const handleMessage = (event: MessageEvent<WorkerResponse>) => {
          const { type } = event.data

          switch (type) {
            case "READY":
              setLoaded(true)
              setIsLoading(false)
              setMessage("FFmpeg loaded successfully")
              break
            case "LOG":
              if ("message" in event.data) {
                const msg = event.data.message
                setLogs((prev) => appendCapped(prev, [msg], MAX_LOG_LINES))
                if (messageRef.current) {
                  messageRef.current.scrollTop = messageRef.current.scrollHeight
                }
              }
              break
            case "PROGRESS":
              if ("progress" in event.data) {
                const p = Math.round(event.data.progress * 100)
                setProgress(p)
                setMessage(`Processing... ${p}%`)
              }
              break
            case "SEGMENT_DATA":
              if ("files" in event.data) {
                const newImages = event.data.files.map((f: any) => {
                  const blob = new Blob([f.data], { type: "image/jpeg" })
                  return { url: URL.createObjectURL(blob), name: f.name }
                })
                extractedCountRef.current += newImages.length
                setImages((prev) =>
                  appendCapped(prev, newImages, MAX_IMAGES, (img) =>
                    URL.revokeObjectURL((img as any).url)
                  )
                )
                setMessage(
                  `Processing... Extracted ${extractedCountRef.current} frames.`
                )
              }
              break
            case "DONE":
              setMessage(
                `Completed! Extracted ${extractedCountRef.current} frames.`
              )
              setProcessing(false)
              break
            case "FATAL":
              if ("error" in event.data) {
                setError(event.data.error)
                setProcessing(false)
                setLoaded(false)
                setIsLoading(true)
              }
              if (workerRef.current) {
                workerRef.current.terminate()
                workerRef.current = null
              }
              {
                const worker = createWorker()
                worker.onmessage = handleMessage
                worker.postMessage({ type: "LOAD", baseURL })
              }
              break
            case "ERROR":
              if ("error" in event.data) {
                setError(event.data.error)
                setProcessing(false)
                setIsLoading(false)
              }
              break
          }
        }

        const worker = createWorker()
        worker.onmessage = handleMessage

        worker.postMessage({ type: "LOAD", baseURL })
      }
    })
    // Only create worker if not exists

    // Cleanup worker on unmount?
    // Usually good practice, but if we want to keep it alive for navigation back/forth,
    // we might want to move it to Context.
    // For this task, local cleanup is fine.
    return () => {
      if (workerRef.current) {
        workerRef.current.terminate()
        workerRef.current = null
      }
    }
  }, [])

  /**
   * 将视频 Base64 转换为 File 对象
   * @param {string} base64String - 视频 Base64 字符串
   * @param {string} fileName - 文件名 (例如 'video.mp4')
   * @returns {File}
   */
  function videoBase64ToFile(base64String: string, fileName: string) {
    // 1. 提取 MIME 类型和数据
    const parts = base64String.split(",")
    const mime = parts[0].match(/:(.*?);/)?.[1] // 可能是 video/mp4, video/webm 等

    // 2. 解码
    const bstr = atob(parts[1])
    let n = bstr.length
    const u8arr = new Uint8Array(n)

    // 3. 填充字节数组
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }

    // 4. 返回 File 对象
    return new File([u8arr], fileName, { type: mime })
  }

  const getServerVideo = async () => {
    const params = {
      data_names: ["6874b86e341d1d0e4c75d0d5.h264"],
      data_type: 0,
      project_id: 9,
    }
    let text
    const response = await getServerImage(params)
    text = `data:video/h264;base64,${response}`

    const fileRes = videoBase64ToFile(text, "6874b86e341d1d0e4c75d0d5.h264")

    // const videoFile = new File([response], "6874b86e341d1d0e4c75d0d5.264", {
    //   type: "video/264",
    // })
    setFile(fileRes)
  }

  function downloadFile(file: File | null) {
    if (!file) return
    // 创建一个临时的 DOM URL 指向内存中的文件
    const url = URL.createObjectURL(file)

    // 创建一个隐藏的 a 标签
    const a = document.createElement("a")
    a.style.display = "none"
    a.href = url
    a.download = file.name // 设置下载后的文件名

    // 将标签添加到文档中并触发点击
    document.body.appendChild(a)
    a.click()

    // 清理工作：移除标签并释放内存 URL
    document.body.removeChild(a)
    window.URL.revokeObjectURL(url)
  }

  const processVideo = () => {
    if (!file || !loaded || !workerRef.current) return

    setProcessing(true)
    setProgress(0)
    extractedCountRef.current = 0
    for (const img of images) URL.revokeObjectURL(img.url)
    setImages([])
    setLogs([])
    setError(null)
    setMessage("Starting processing...")

    // Extract 1 frame per second: -vf fps=1
    // Optimize: Scale down to 720p max width to save memory
    workerRef.current.postMessage({
      type: "EXEC",
      file,
      args: [
        "-vf",
        "fps=1,scale='min(720,iw)':-1",
        "-q:v",
        "2",
        "frame_%03d.jpg",
      ],
      outputPattern: "frame_",
    })
  }

  const downloadAll = () => {
    images.forEach((img, index) => {
      setTimeout(() => {
        const a = document.createElement("a")
        a.href = img.url
        a.download = img.name
        a.click()
      }, index * 200)
    })
  }

  return (
    <Container size="lg" py="xl">
      <Stack gap="lg">
        <Title order={2}>Video Frame Extractor (Worker + Local WASM)</Title>
        <Text c="dimmed">
          Extract frames from your video files purely in the browser using
          FFmpeg.wasm (Async Worker).
        </Text>

        {error && (
          <Alert
            icon={<IconAlertCircle size={16} />}
            title="Error"
            color="red"
            withCloseButton
            onClose={() => setError(null)}>
            {error}
          </Alert>
        )}

        <Card withBorder shadow="sm" p="lg" radius="md">
          <Flex gap={"md"}>
            <Button onClick={getServerVideo}>getServerVideo</Button>
            <Button
              onClick={() => {
                downloadFile(file)
              }}>
              downloadFile
            </Button>
          </Flex>

          <Stack gap="md">
            <FileInput
              label="Select Video File"
              placeholder="Click to select MP4, WebM..."
              // accept="video/*"
              leftSection={<IconMovie size={16} />}
              value={file}
              onChange={setFile}
              disabled={!loaded || processing}
            />

            {!loaded && isLoading && (
              <Group>
                <Loader size="sm" />
                <Text size="sm">Loading FFmpeg core...</Text>
              </Group>
            )}

            {loaded && (
              <Group justify="flex-end">
                <Button
                  onClick={processVideo}
                  disabled={!file || processing}
                  loading={processing}
                  leftSection={<IconPhoto size={16} />}>
                  {processing ? "Processing..." : "Start Extraction"}
                </Button>
              </Group>
            )}

            {processing && (
              <Stack gap="xs">
                <Text size="sm">{message}</Text>
                <Progress value={progress} animated />
              </Stack>
            )}
          </Stack>
        </Card>

        {logs.length > 0 && (
          <Card withBorder shadow="sm" p="xs" radius="md" bg="gray.0">
            <Text size="xs" fw={500} mb="xs">
              Logs
            </Text>
            <ScrollArea h={100} type="always" viewportRef={messageRef}>
              <Box
                style={{
                  whiteSpace: "pre-wrap",
                  fontFamily: "monospace",
                  fontSize: "11px",
                }}>
                {logs.map((log, i) => (
                  <div key={i}>{log}</div>
                ))}
              </Box>
            </ScrollArea>
          </Card>
        )}

        {images.length > 0 && (
          <Stack gap="md">
            <Group justify="space-between" align="center">
              <Title order={3}>Extracted Frames ({images.length})</Title>
              <Button
                variant="outline"
                leftSection={<IconDownload size={16} />}
                onClick={downloadAll}>
                Download All
              </Button>
            </Group>

            <SimpleGrid cols={{ base: 2, sm: 3, md: 4 }} spacing="md">
              {images.map((img) => (
                <Card
                  key={img.name}
                  shadow="sm"
                  padding="xs"
                  radius="md"
                  withBorder>
                  <Card.Section>
                    <Image
                      src={img.url}
                      height={160}
                      alt={img.name}
                      fit="cover"
                    />
                  </Card.Section>
                  <Group justify="space-between" mt="xs" mb="xs">
                    <Text fw={500} size="xs" truncate>
                      {img.name}
                    </Text>
                    <ActionIcon
                      variant="light"
                      color="blue"
                      component="a"
                      href={img.url}
                      download={img.name}>
                      <IconDownload size={14} />
                    </ActionIcon>
                  </Group>
                </Card>
              ))}
            </SimpleGrid>
          </Stack>
        )}
      </Stack>
    </Container>
  )
}
