import { $, component$, Signal, useSignal, useTask$ } from "@builder.io/qwik";
import { useNanostore$ } from "~/hooks/nanostores";
import { api } from "~/lib/api";
import { dashboardFiles } from "~/lib/stores";
import { StereoFile } from "~/lib/types";
import { SolarClipboardAddBold, SolarDownloadMinimalisticBold, SolarTrashBin2Bold } from "../misc/Icons";

type FileProps = {
    file: StereoFile;
}

const formatSize = (bytes: number) => {
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
    return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
}

export default component$(({ file }: FileProps) => {
    const files = useNanostore$<StereoFile[]>(dashboardFiles);

    const deleteFile = $(async (uid: string, name: string) => {
        if (!confirm("Are you sure you want to delete this file?")) return;
        console.log(await api.delete(uid, name));
        files.value = await api.list();
    });

    const addFileToClipboard = $(async () => {
        const response = await api.file(file.Name);
        const data = await response.blob();
        let mime = data.type || "application/octet-stream";
        let clip;

        if (navigator.clipboard && window.ClipboardItem) {
            if (mime === "image/jpeg" || mime === "image/jpg") {
                const img = document.createElement("img");
                img.src = URL.createObjectURL(data);
                await new Promise((res) => (img.onload = res));
                const canvas = document.createElement("canvas");
                canvas.width = img.width;
                canvas.height = img.height;
                const ctx = canvas.getContext("2d");
                ctx?.drawImage(img, 0, 0);
                const png = await new Promise<Blob>((resolve) =>
                    canvas.toBlob((b) => resolve(b!), "image/png")
                );
                mime = "image/png";
                clip = new ClipboardItem({ [mime]: png });
            } else {
                clip = new ClipboardItem({ [mime]: data });
            }

            try {
                await navigator.clipboard.write([clip]);
                alert("File added to clipboard successfully!");
            } catch (error) {
                console.error("Failed to add file to clipboard:", error);
                alert("Failed to add file to clipboard. Please try again.");
            }
        } else {
            alert("Clipboard API not supported in this browser.");
        }
    });
    
    return (
        <div class="rounded-xl bg-neutral-900 flex flex-col group overflow-hidden hover:bg-neutral-800 transition-all duration-200">
            <div class="relative">
                <a
                    href={`/api/${file.ID}`} 
                    target="_blank"
                    class="flex w-full h-60 overflow-clip"
                >
                    <div class="flex flex-grow group-hover:scale-105 transition-all duration-500 bg-neutral-800">
                        <FilePreview file={file} />
                    </div>   
                </a>

                <div class="absolute bottom-2 right-2 gap-2 z-10 group-hover:flex hidden duration-200 transition-all">
                    <a
                        class="bg-neutral-600/40 backdrop-blur-lg hover:bg-neutral-600/75 transition-all duration-200 text-white p-2 rounded-lg active:scale-95"
                        href={`/api/${file.ID}`}
                        target="_blank"
                    >
                        <SolarDownloadMinimalisticBold class="w-6 h-6"/>
                    </a>
                    
                    <button
                        class="bg-green-600/50 backdrop-blur-lg hover:bg-green-600/75 transition-all duration-200 text-white p-2 rounded-lg active:scale-95"
                        onClick$={async () => await addFileToClipboard()}
                    >
                        <SolarClipboardAddBold class="w-6 h-6"/>
                    </button>
                    
                    <button
                        class="bg-red-600/50 backdrop-blur-lg hover:bg-red-600/75 transition-all duration-200 text-white p-2 rounded-lg active:scale-95"
                        onClick$={async () => await deleteFile(file.Owner, file.Name)}
                    >
                        <SolarTrashBin2Bold class="w-6 h-6"/>
                    </button>
                </div>
            </div>
            
            <div class="flex justify-center items-center h-full">
                <div class="p-4 flex flex-col w-full text-center">
                    <p class="text-lg font-semibold text-white w-full truncate">
                        { file.Name || "Untitled" }
                        </p>
                    <div class="flex gap-1 text-sm text-neutral-500 items-center justify-center">
                        <span>{ formatSize(file.Size) }</span>
                        <span class="text-neutral-600">•</span>
                        <span>Uploaded on { new Date(file.CreatedAt).toLocaleDateString() }</span>
                    </div>
                </div>
            </div>
        </div>
    )
})

const FilePreview = component$(({ file }: FileProps) => {
    type FileType =
        | "image"
        | "video"
        | "audio"
        | "other";

    const type: Signal<FileType> = useSignal<FileType>("other");
    const extension = file.Name.split('.').pop()?.toLowerCase() || "";

    useTask$(async () => {
        if (
            ["png", "jpg", "jpeg", "gif"]
            .includes(extension)) type.value = "image";

        else if (
            ["mp4", "webm", "ogg", "avi", "mov", "mkv"]
            .includes(extension)) type.value = "video";
        else if (
            ["mp3", "wav", "ogg", "flac", "aac"]
            .includes(extension)) type.value = "audio";

        else type.value = "other";
    });

    switch (type.value) {
        case "image":
            return (
                <div class="w-full h-60 object-cover flex-grow relative">
                    <img
                        width={400}
                        height={300}
                        src={`/api/${file.ID}`}
                        alt={file.Name}
                        class="w-full h-60 object-cover flex-grow"
                    />
                </div>
            );
        case "video":
            return (
                <div class="w-full h-60 object-cover flex-grow relative">
                    <video
                        width={400}
                        height={300}
                        src={`/api/${file.ID}`}
                        class="w-full h-60 object-cover flex-grow"
                        controls
                        autoplay
                        muted
                    >
                        <div class="w-full h-60 flex items-center justify-center">
                            <p class="text-white/50 text-lg font-light">
                                Preview not available
                            </p>
                        </div>
                    </video>
                </div>
            );
        case "audio":
            return (
                <div class="w-full h-60 flex items-center justify-center p-2">
                    <audio
                        controls
                        class="w-full h-12"
                        src={`/api/${file.ID}`}
                    >
                        Your browser does not support the audio element.
                    </audio>
                </div>
            );
        case "other":
        default:
            return (
                <div class="w-full h-60 flex items-center justify-center">
                    <p class="text-white/50 text-lg font-light">
                        Preview not available
                    </p>
                </div>
            );
        }
});