import React, { useEffect, useRef, useState } from "react"
import { SVGS } from "../assets/svgs"
import { ContentCard } from "./ContentCard"
import useStore from "../utils/store"
import toast from "react-hot-toast"
import CreatorSocket from "../utils/socket"

const socketClient = new CreatorSocket("")

const allowedTypes = [
  "application/pdf",
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "text/plain",
  "text/markdown",
]

export interface ParsedFile {
  name: string
  text: string
  status: "PROCESSING" | "SUCCESS" | "ERROR"
  notificationId: string
}

interface FileUploaderProps {
  styledAs?: "button" | "card"
  onFinish?: (files: ParsedFile[]) => void
}

const UploadedFileCard = ({ idx, file }: { idx: number; file: ParsedFile }) => {
  const setUploadedFiles = useStore((state) => state.setUploadedFiles)
  const uploadedFiles = useStore((state) => state.uploadedFiles)

  const handleUpdate = (data: any) => {
    if (data.text) {
      setUploadedFiles(
        uploadedFiles.map((f, i) =>
          i === idx ? { ...f, status: "SUCCESS", text: data.text } : f
        )
      )
    } else {
      setUploadedFiles(
        uploadedFiles.map((f, i) => (i === idx ? { ...f, status: "ERROR" } : f))
      )
    }
  }

  useEffect(() => {
    if (file.status === "SUCCESS") return

    console.log("CONNECTING TO SOCKET", file.notificationId)
    socketClient.connect()
    socketClient.on(file.notificationId, handleUpdate)

    socketClient.emit("registerNotification", {
      notificationId: file.notificationId,
    })

    return () => {
      socketClient.off(file.notificationId, handleUpdate)
      socketClient.disconnect()
    }
  }, [])

  return (
    <div
      className={
        "p-3 rounded-md shadow-sm text-sm text-gray-800 text-left flex items-center gap-2" +
        (file.status === "PROCESSING"
          ? " bg-gray-100"
          : file.status === "ERROR"
          ? " bg-red-100"
          : " bg-white")
      }
      title={file.name}
    >
      {file.status === "PROCESSING" && (
        <div className="w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
      )}
      {file.status === "ERROR" && (
        <span className="text-red-500 font-bold">Error!</span>
      )}

      <strong className="truncate">{file.name.slice(0, 20)}...</strong>

      <button
        className={
          "ml-auto cursor-pointer transition-colors " +
          (file.status === "PROCESSING"
            ? "text-gray-400 cursor-not-allowed"
            : "text-gray-600 hover:text-red-500")
        }
        onClick={
          () => setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx))
          // Set the file as error
          // setUploadedFiles(
          //   uploadedFiles.map((f, i) =>
          //     i === idx ? { ...f, status: "ERROR" } : f
          //   )
          // )
        }
      >
        {SVGS.trash}
      </button>
    </div>
  )
}

const FileUploader: React.FC<FileUploaderProps> = ({
  styledAs = "button",
  onFinish,
}) => {
  // const rigoToken = useStore((state) => state.auth.rigoToken)
  const publicToken = useStore((state) => state.auth.publicToken)
  const inputRef = useRef<HTMLInputElement>(null)
  const uploadedFiles = useStore((state) => state.uploadedFiles)
  const setUploadedFiles = useStore((state) => state.setUploadedFiles)
  const [isDragging, setIsDragging] = useState(false)
  const [isLoading, setIsLoading] = useState(false)

  const extractTextFromFile = async (file: File): Promise<ParsedFile> => {
    const { type, name } = file

    if (type === "text/plain" || type === "text/markdown") {
      const text = await file.text()
      return { name, text, status: "SUCCESS", notificationId: "" }
    }

    const formData = new FormData()
    formData.append("file", file)

    const loadingToast = toast.loading(`Processing ${file.name}...`)
    try {
      const res = await fetch("/read-document", {
        method: "POST",
        headers: {
          "x-public-token": publicToken,
        },
        body: formData,
      })

      if (!res.ok) throw new Error(`Failed to read ${file.name}`)
      const data = await res.json()
      toast.success(`Processing ${file.name}`, { id: loadingToast })
      return {
        name,
        text: "",
        status: data.status,
        notificationId: data.notificationId,
      }
    } catch (err: any) {
      toast.error(`❌ ${file.name} failed: ${err.message}`, {
        id: loadingToast,
      })
      return { name, text: "", status: "ERROR", notificationId: "" }
    }
  }

  const parseFiles = async (files: FileList | File[]) => {
    const validFiles = Array.from(files).filter((file) =>
      allowedTypes.includes(file.type)
    )
    if (validFiles.length === 0) {
      toast.error("No valid files selected")
      return
    }

    setIsLoading(true)
    const parsed = await Promise.all(validFiles.map(extractTextFromFile))
    const newFiles = [...uploadedFiles, ...parsed]

    setUploadedFiles(newFiles.filter((file) => file.status !== "ERROR"))
    setIsLoading(false)
  }

  const handleInput = async (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return
    await parseFiles(e.target.files)
  }

  const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    setIsDragging(false)
    if (e.dataTransfer.files.length > 0) {
      parseFiles(e.dataTransfer.files)
    }
  }

  return (
    <div className="flex flex-col gap-2 w-full">
      {uploadedFiles.length > 0 && styledAs === "card" && (
        <div className="w-full flex flex-row gap-2 flex-wrap justify-center items-center">
          {uploadedFiles.map((file, idx) => (
            <UploadedFileCard key={idx} idx={idx} file={file} />
          ))}
        </div>
      )}

      {styledAs === "button" && (
        <div className="flex items-center justify-end gap-2 w-100">
          <button
            type="button"
            className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
            onClick={() => inputRef.current?.click()}
          >
            {isLoading ? (
              <div className="loader w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
            ) : (
              SVGS.clip
            )}
          </button>
        </div>
      )}

      {styledAs === "card" && (
        <>
          <ContentCard
            description={
              isDragging
                ? "Drop it here"
                : isLoading
                ? "Processing..."
                : "Upload a PDF or DOCX file or drag it here"
            }
            icon={isDragging ? SVGS.clip : SVGS.pdf}
            onClick={() => inputRef.current?.click()}
            onDragOver={(e) => {
              e.preventDefault()
              setIsDragging(true)
            }}
            onDragLeave={() => setIsDragging(false)}
            onDrop={handleDrop}
            className={isDragging ? "border-blue-600 bg-blue-50" : ""}
          />
          <button
            disabled={uploadedFiles.some((file) => file.status !== "SUCCESS")}
            className="bg-blue-500 text-white px-4 py-2 rounded-md cursor-pointer disabled:opacity-50"
            onClick={() => {
              onFinish?.(uploadedFiles)
            }}
          >
            🚀 Finish
          </button>
        </>
      )}

      <input
        ref={inputRef}
        type="file"
        multiple
        accept=".pdf,.docx,.txt,.md"
        onChange={handleInput}
        style={{ display: "none" }}
      />
    </div>
  )
}

export default FileUploader
