"use client"

import { useState, useEffect, useCallback, type ChangeEvent, type FormEvent } from "react"
import { ReloadIcon } from "@radix-ui/react-icons"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { type NostrEvent } from "nostr-tools"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import {
    Drawer,
    DrawerContent,
    DrawerHeader,
    DrawerTitle,
    DrawerDescription,
    DrawerFooter,
} from "@/components/ui/drawer"
import { Spinner } from "./spinner"
import { signEvent } from "@/lib/utils"

async function calculateBlurhash(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
        const canvas = document.createElement("canvas")
        const ctx = canvas.getContext("2d")
        const img = new Image()
        img.crossOrigin = "anonymous"
        img.onload = () => {
            canvas.width = 32
            canvas.height = 32
            ctx?.drawImage(img, 0, 0, 32, 32)
            const imageData = ctx?.getImageData(0, 0, 32, 32)
            if (imageData) {
                // Mock blurhash calculation - in a real app you'd use the blurhash library
                const mockBlurhash = "LGF5?xYk^6#M@-5c,1J5@[or[Q6."
                resolve(mockBlurhash)
            } else {
                reject(new Error("Failed to get image data"))
            }
        }
        img.onerror = reject
        img.src = URL.createObjectURL(file)
    })
}

async function calculateSHA256(file: File): Promise<string> {
    // In a browser environment, we'd use the Web Crypto API
    // This is a simplified mock implementation
    return new Promise((resolve) => {
        setTimeout(() => {
            // Generate a random SHA256-like hash for demo purposes
            const mockHash = Array.from({ length: 64 }, () => "0123456789abcdef"[Math.floor(Math.random() * 16)]).join("")
            resolve(mockHash)
        }, 500)
    })
}

const UploadComponent = () => {
    const { createHash } = require("crypto")
    const loginType = typeof window !== "undefined" ? window.localStorage.getItem("loginType") : null
    const [previewUrl, setPreviewUrl] = useState("")
    const [isLoading, setIsLoading] = useState(false)
    const [isDrawerOpen, setIsDrawerOpen] = useState(false)
    const [uploadedNoteId, setUploadedNoteId] = useState("")
    const [retryCount, setRetryCount] = useState(0)
    const [shouldFetch, setShouldFetch] = useState(false)
    const [serverChoice, setServerChoice] = useState("blossom.band")
    const [events, setEvents] = useState<any[]>([])
    const [isNoteLoading, setIsNoteLoading] = useState(false)

    useEffect(() => {
        if (uploadedNoteId) {
            setShouldFetch(true)
        }
    }, [uploadedNoteId])

    useEffect(() => {
        let timeoutId: NodeJS.Timeout

        if (shouldFetch && events.length === 0 && !isNoteLoading) {
            setIsNoteLoading(true)

            // Simulate fetching events
            timeoutId = setTimeout(() => {
                setIsNoteLoading(false)
                // After a few retries, simulate finding the event
                if (retryCount >= 2) {
                    setEvents([{ id: uploadedNoteId }])
                } else {
                    setRetryCount((prevCount) => prevCount + 1)
                }
            }, 2000)
        }

        return () => {
            if (timeoutId) {
                clearTimeout(timeoutId)
            }
        }
    }, [shouldFetch, events, isNoteLoading, retryCount, uploadedNoteId])

    const handleRetry = useCallback(() => {
        setRetryCount((prevCount) => prevCount + 1)
        setShouldFetch(false)
        setTimeout(() => setShouldFetch(true), 100)
    }, [])

    const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
        const file = event.target.files?.[0]
        if (file) {
            const url = URL.createObjectURL(file)
            setPreviewUrl(url)

            return () => URL.revokeObjectURL(url)
        }
    }

    const handleServerChange = (value: string) => {
        setServerChoice(value)
    }

    async function onSubmit(event: FormEvent<HTMLFormElement>) {
        event.preventDefault()
        setIsLoading(true)

        const formData = new FormData(event.currentTarget)
        const desc = formData.get("description") as string
        const file = formData.get("file") as File
        let sha256 = ""
        let finalNoteContent = desc
        let finalFileUrl = ""
        console.log("File:", file)

        if (!desc && !file.size) {
            alert("Please enter a description and/or upload a file")
            setIsLoading(false)
            return
        }

        // If file is present, upload it to the media server
        if (file) {
            const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> => {
                return new Promise((resolve, reject) => {
                    const reader = new FileReader()
                    reader.onload = () => resolve(reader.result as ArrayBuffer)
                    reader.onerror = () => reject(reader.error)
                    reader.readAsArrayBuffer(file)
                })
            }

            try {
                const arrayBuffer = await readFileAsArrayBuffer(file)
                const hashBuffer = createHash("sha256").update(Buffer.from(arrayBuffer)).digest()
                sha256 = hashBuffer.toString("hex")

                const unixNow = () => Math.floor(Date.now() / 1000)
                const newExpirationValue = () => (unixNow() + 60 * 5).toString()

                const pubkey = window.localStorage.getItem("pubkey")
                const createdAt = Math.floor(Date.now() / 1000)

                // alert("SHA256: " + sha256)

                // Create auth event for blossom auth via nostr
                const authEvent: NostrEvent = {
                    kind: 24242,
                    // content: desc,
                    content: "File upload",
                    created_at: createdAt,
                    tags: [
                        ["t", "media"],
                        ["x", sha256],
                        ["expiration", newExpirationValue()],
                    ],
                    pubkey: "", // Add a placeholder for pubkey
                    id: "", // Add a placeholder for id
                    sig: "", // Add a placeholder for sig
                }

                console.log(authEvent)

                // Sign auth event
                const authEventSigned = (await signEvent(loginType, authEvent)) as NostrEvent
                // authEventSigned as base64 encoded string
                const authString = Buffer.from(JSON.stringify(authEventSigned)).toString("base64")

                const blossomServer = "https://" + serverChoice

                await fetch(blossomServer + "/media", {
                    method: "PUT",
                    body: file,
                    headers: { authorization: "Nostr " + authString },
                }).then(async (res) => {
                    if (res.ok) {
                        const responseText = await res.text()
                        const responseJson = JSON.parse(responseText)
                        finalFileUrl = responseJson.url
                        sha256 = responseJson.sha256

                        let blurhash = ""
                        if (file && file.type.startsWith("image/")) {
                            try {
                                blurhash = await calculateBlurhash(file)
                            } catch (error) {
                                console.error("Error calculating blurhash:", error)
                            }
                        }

                        if (finalFileUrl) {
                            const image = new Image()
                            image.src = URL.createObjectURL(file)
                            await new Promise((resolve) => {
                                image.onload = resolve
                            })

                            finalNoteContent = desc
                        }

                        setIsLoading(false)
                        if (finalFileUrl != null) {
                            setIsDrawerOpen(true)
                            setShouldFetch(true)
                            setRetryCount(0)
                        }
                    } else {
                        // alert(await res.text())
                        throw new Error("Failed to upload file: " + (await res.text()))
                    }
                })
            } catch (error) {
                alert(error)
                console.error("Error reading file:", error)
                setIsLoading(false)
            }
        }

    }

    return (
        <>
            <div className="w-full max-w-2xl mx-auto">
                <form className="space-y-4" onSubmit={onSubmit}>
                    <div className="grid w-full items-center gap-1.5">
                        <Label htmlFor="file">Upload Image</Label>
                        <Input id="file" name="file" type="file" accept="image/*" onChange={handleFileChange} />
                    </div>

                    <div className="grid grid-cols-2 w-full items-center gap-1.5">
                        <Label htmlFor="server-select">Upload to</Label>
                        <Select onValueChange={handleServerChange} value={serverChoice}>
                            <SelectTrigger className="w-full" id="server-select">
                                <SelectValue placeholder={serverChoice} />
                            </SelectTrigger>
                            <SelectContent>
                                <SelectItem value="blossom.band">blossom.band</SelectItem>
                            </SelectContent>
                        </Select>
                    </div>

                    {previewUrl && (
                        <div className="mt-4 rounded-md overflow-hidden">
                            <img src={previewUrl || "/placeholder.svg"} alt="Preview" className="w-full max-h-80 object-contain" />
                        </div>
                    )}

                    {isLoading ? (
                        <Button className="w-full" disabled>
                            Uploading... <ReloadIcon className="ml-2 h-4 w-4 animate-spin" />
                        </Button>
                    ) : (
                        <Button className="w-full" type="submit">
                            Upload
                        </Button>
                    )}
                </form>
            </div>

            <Drawer open={isDrawerOpen} onOpenChange={setIsDrawerOpen}>
                <DrawerContent>
                    <DrawerHeader>
                        <DrawerTitle>Upload Status</DrawerTitle>
                        <DrawerDescription>
                            {isNoteLoading ? (
                                <div className="flex items-center space-x-2">
                                    <Spinner />
                                    <span>Checking note status...</span>
                                </div>
                            ) : events.length > 0 ? (
                                <div
                                    className="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative"
                                    role="alert"
                                >
                                    <strong className="font-bold">Success!</strong>
                                    <span className="block sm:inline"> Note found with ID: </span>
                                    <span className="block sm:inline font-mono">
                                        {`${uploadedNoteId.slice(0, 5)}...${uploadedNoteId.slice(-3)}`}
                                    </span>
                                </div>
                            ) : (
                                <p>Note not found. It may take a moment to propagate.</p>
                            )}
                        </DrawerDescription>
                    </DrawerHeader>
                    <DrawerFooter className="flex flex-col space-y-2">
                        {events.length === 0 && (
                            <Button onClick={handleRetry} variant="outline" className="w-full">
                                Retry Now
                            </Button>
                        )}
                        <Button asChild className="w-full">
                            <a href={`/note/${uploadedNoteId}`}>View Note</a>
                        </Button>
                        <Button variant="outline" onClick={() => setIsDrawerOpen(false)} className="w-full">
                            Close
                        </Button>
                    </DrawerFooter>
                </DrawerContent>
            </Drawer>
        </>
    )
}

export default UploadComponent
