import { useState, useEffect } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Loader2, Download, Check, AlertCircle, Brain, RefreshCw } from "lucide-react";
import { zipSync, strToU8 } from "fflate";
import type { NormalizedPost } from "@/lib/grabber/sites";

interface ImageDescriberModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  posts: NormalizedPost[];
}

export function ImageDescriberModal({ open, onOpenChange, posts }: ImageDescriberModalProps) {
  const [descriptions, setDescriptionState] = useState<
    Record<string, { text: string; loading: boolean; error?: string }>
  >({});
  const [downloadingZip, setDownloadingZip] = useState<Record<string, boolean>>({});

  useEffect(() => {
    if (!open) return;

    let active = true;
    const runDescriptions = async () => {
      for (const post of posts) {
        if (!active) break;
        
        // Skip if already generating or has description
        const currentState = descriptions[post.id];
        if (currentState && (currentState.text || currentState.loading)) {
          continue;
        }

        setDescriptionState((prev) => ({
          ...prev,
          [post.id]: { text: "", loading: true },
        }));

        try {
          const res = await fetch("/api/describe-image", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ imageUrl: post.fileUrl }),
          });
          const data = await res.json();
          if (!active) break;

          if (data.success && data.description) {
            setDescriptionState((prev) => ({
              ...prev,
              [post.id]: { text: data.description, loading: false },
            }));
          } else {
            setDescriptionState((prev) => ({
              ...prev,
              [post.id]: {
                text: "",
                loading: false,
                error: data.error || "Failed to generate description",
              },
            }));
          }
        } catch (err) {
          if (!active) break;
          setDescriptionState((prev) => ({
            ...prev,
            [post.id]: {
              text: "",
              loading: false,
              error: err instanceof Error ? err.message : "Inference error",
            },
          }));
        }
      }
    };

    runDescriptions();

    return () => {
      active = false;
    };
  }, [open, posts]);

  const handleDescribeSingle = async (post: NormalizedPost) => {
    setDescriptionState((prev) => ({
      ...prev,
      [post.id]: { text: "", loading: true, error: undefined },
    }));

    try {
      const res = await fetch("/api/describe-image", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ imageUrl: post.fileUrl }),
      });
      const data = await res.json();

      if (data.success && data.description) {
        setDescriptionState((prev) => ({
          ...prev,
          [post.id]: { text: data.description, loading: false },
        }));
      } else {
        setDescriptionState((prev) => ({
          ...prev,
          [post.id]: {
            text: "",
            loading: false,
            error: data.error || "Failed to generate description",
          },
        }));
      }
    } catch (err) {
      setDescriptionState((prev) => ({
        ...prev,
        [post.id]: {
          text: "",
          loading: false,
          error: err instanceof Error ? err.message : "Inference error",
        },
      }));
    }
  };

  const downloadSingleDescZip = async (post: NormalizedPost, description: string) => {
    setDownloadingZip((prev) => ({ ...prev, [post.id]: true }));
    try {
      const response = await fetch(post.fileUrl);
      if (!response.ok) throw new Error("Failed to fetch image file");
      const buffer = await response.arrayBuffer();
      const imgBytes = new Uint8Array(buffer);

      const zipFiles: Record<string, Uint8Array> = {};
      const ext = post.ext || "jpg";
      zipFiles[`image.${ext}`] = imgBytes;
      zipFiles[`desc.txt`] = strToU8(description);

      const zipped = zipSync(zipFiles, { level: 0 });
      const blob = new Blob([zipped], { type: "application/zip" });
      const url = URL.createObjectURL(blob);

      const a = document.createElement("a");
      a.href = url;
      a.download = `image_${post.id}_with_description.zip`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch (err) {
      alert(`Download failed: ${err instanceof Error ? err.message : "unknown error"}`);
    } finally {
      setDownloadingZip((prev) => ({ ...prev, [post.id]: false }));
    }
  };

  // Progress stats
  const describedCount = posts.filter((p) => descriptions[p.id]?.text).length;
  const loadingCount = posts.filter((p) => descriptions[p.id]?.loading).length;

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-4xl h-[90vh] flex flex-col p-6">
        <DialogHeader className="flex flex-row justify-between items-center border-b pb-4">
          <div>
            <DialogTitle className="text-xl font-bold flex items-center gap-2">
              <Brain className="w-5 h-5 text-purple-600 animate-pulse" />
              AI Image Describer (GGUF LLaVA)
            </DialogTitle>
            <DialogDescription className="text-xs text-muted-foreground mt-1">
              Described {describedCount} of {posts.length} selected images{" "}
              {loadingCount > 0 && "(Processing sequentially...)"}
            </DialogDescription>
          </div>
        </DialogHeader>

        <ScrollArea className="flex-1 pr-4 py-4">
          <div className="space-y-6">
            {posts.map((post) => {
              const state = descriptions[post.id] || { text: "", loading: false };
              const isZipping = downloadingZip[post.id];

              return (
                <div
                  key={post.id}
                  className="flex flex-col md:flex-row gap-4 p-4 rounded-lg border bg-muted/10 hover:bg-muted/20 transition"
                >
                  <div className="w-full md:w-48 h-48 rounded-md bg-muted overflow-hidden relative flex-shrink-0 flex items-center justify-center">
                    <img
                      src={post.previewUrl}
                      alt={`Post ${post.id}`}
                      className="w-full h-full object-cover"
                    />
                    <div className="absolute top-2 left-2 bg-black/60 text-white text-[10px] px-2 py-0.5 rounded font-mono">
                      ID: {post.id}
                    </div>
                  </div>

                  <div className="flex-1 flex flex-col justify-between min-w-0">
                    <div className="space-y-2">
                      <div className="flex items-center gap-2">
                        <span className="font-semibold text-sm uppercase text-muted-foreground">
                          Description
                        </span>
                        {state.loading && (
                          <span className="flex items-center gap-1 text-xs text-purple-600 font-medium">
                            <Loader2 className="w-3.5 h-3.5 animate-spin" />
                            Analyzing image...
                          </span>
                        )}
                        {state.text && (
                          <span className="flex items-center gap-1 text-xs text-emerald-600 font-medium">
                            <Check className="w-3.5 h-3.5" />
                            Completed
                          </span>
                        )}
                        {state.error && (
                          <span className="flex items-center gap-1 text-xs text-destructive font-medium">
                            <AlertCircle className="w-3.5 h-3.5" />
                            Error: {state.error}
                          </span>
                        )}
                      </div>

                      <div className="text-sm text-foreground bg-muted/40 p-3 rounded-md min-h-[100px] whitespace-pre-wrap">
                        {state.loading && (
                          <div className="flex flex-col items-center justify-center h-16 text-muted-foreground gap-2">
                            <Loader2 className="w-6 h-6 animate-spin text-purple-600" />
                            <p className="text-xs">Running GGUF multimodal inference...</p>
                          </div>
                        )}
                        {!state.loading && !state.text && !state.error && (
                          <span className="text-muted-foreground italic">
                            Waiting in sequence queue...
                          </span>
                        )}
                        {state.error && (
                          <div className="flex flex-col gap-2">
                            <span className="text-destructive text-xs">{state.error}</span>
                            <Button
                              variant="outline"
                              size="sm"
                              className="w-24 text-xs h-8"
                              onClick={() => handleDescribeSingle(post)}
                            >
                              <RefreshCw className="w-3 h-3 mr-1" /> Retry
                            </Button>
                          </div>
                        )}
                        {state.text && <p className="leading-relaxed font-sans">{state.text}</p>}
                      </div>
                    </div>

                    {state.text && (
                      <div className="flex justify-end mt-4">
                        <Button
                          onClick={() => downloadSingleDescZip(post, state.text)}
                          disabled={isZipping}
                          size="sm"
                          className="bg-purple-600 hover:bg-purple-700 text-white font-medium text-xs h-9"
                        >
                          {isZipping ? (
                            <Loader2 className="w-3.5 h-3.5 mr-1 animate-spin" />
                          ) : (
                            <Download className="w-3.5 h-3.5 mr-1" />
                          )}
                          Download image.png + desc.txt
                        </Button>
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </ScrollArea>
      </DialogContent>
    </Dialog>
  );
}
