"use client";

import * as React from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Upload, Search, Trash2, ImageIcon, Video, FileText, Check, Loader2 } from "lucide-react";
import { toast } from "sonner";

export type MediaItem = {
  id: string;
  filename: string;
  originalName: string;
  url: string;
  mimeType: string;
  size: number;
  width?: number | null;
  height?: number | null;
  type: string;
  altText?: string | null;
  createdAt: string;
};

export function MediaPicker({
  open,
  onOpenChange,
  onSelect,
  accept = "image",
}: {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  onSelect: (item: MediaItem) => void;
  accept?: "image" | "video" | "all";
}) {
  const [items, setItems] = React.useState<MediaItem[]>([]);
  const [loading, setLoading] = React.useState(false);
  const [uploading, setUploading] = React.useState(false);
  const [search, setSearch] = React.useState("");
  const [tab, setTab] = React.useState(accept === "video" ? "video" : accept === "image" ? "image" : "all");
  const [selected, setSelected] = React.useState<MediaItem | null>(null);
  const fileRef = React.useRef<HTMLInputElement>(null);

  const fetchMedia = React.useCallback(async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (tab !== "all") params.set("type", tab);
      if (search) params.set("q", search);
      const res = await fetch(`/api/media?${params}`);
      const data = await res.json();
      setItems(data.items || []);
    } catch {
      toast.error("Failed to load media");
    } finally {
      setLoading(false);
    }
  }, [tab, search]);

  React.useEffect(() => {
    if (open) fetchMedia();
  }, [open, fetchMedia]);

  const handleUpload = async (files: FileList) => {
    if (!files.length) return;
    setUploading(true);
    try {
      const fd = new FormData();
      Array.from(files).forEach((f) => fd.append("files", f));
      const res = await fetch("/api/media", { method: "POST", body: fd });
      if (!res.ok) throw new Error();
      const data = await res.json();
      toast.success(`Uploaded ${data.items.length} file(s)`);
      fetchMedia();
    } catch {
      toast.error("Upload failed");
    } finally {
      setUploading(false);
      if (fileRef.current) fileRef.current.value = "";
    }
  };

  const handleDelete = async (id: string) => {
    if (!confirm("Delete this file permanently?")) return;
    try {
      await fetch(`/api/media/${id}`, { method: "DELETE" });
      toast.success("Deleted");
      setItems((prev) => prev.filter((i) => i.id !== id));
      if (selected?.id === id) setSelected(null);
    } catch {
      toast.error("Delete failed");
    }
  };

  const confirmSelect = () => {
    if (selected) {
      onSelect(selected);
      onOpenChange(false);
      setSelected(null);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-4xl max-h-[85vh] overflow-hidden flex flex-col">
        <DialogHeader>
          <DialogTitle>Media Library</DialogTitle>
          <DialogDescription>Select an existing file or upload new ones.</DialogDescription>
        </DialogHeader>

        <div className="flex flex-col sm:flex-row gap-3 items-stretch sm:items-center justify-between">
          <Tabs value={tab} onValueChange={setTab} className="w-full sm:w-auto">
            <TabsList>
              <TabsTrigger value="all">All</TabsTrigger>
              {accept !== "video" && <TabsTrigger value="image">Images</TabsTrigger>}
              {accept !== "image" && <TabsTrigger value="video">Videos</TabsTrigger>}
            </TabsList>
          </Tabs>
          <div className="flex gap-2 w-full sm:w-auto">
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
              <Input
                placeholder="Search..."
                value={search}
                onChange={(e) => setSearch(e.target.value)}
                onKeyDown={(e) => e.key === "Enter" && fetchMedia()}
                className="pl-9 h-9"
              />
            </div>
            <input
              ref={fileRef}
              type="file"
              multiple
              accept={accept === "image" ? "image/*" : accept === "video" ? "video/*" : "*/*"}
              className="hidden"
              onChange={(e) => e.target.files && handleUpload(e.target.files)}
            />
            <Button onClick={() => fileRef.current?.click()} disabled={uploading} size="sm" className="brand-gradient text-white">
              {uploading ? <Loader2 className="size-4 mr-1.5 animate-spin" /> : <Upload className="size-4 mr-1.5" />}
              Upload
            </Button>
          </div>
        </div>

        <div className="flex-1 overflow-y-auto -mx-1 px-1 min-h-[300px]">
          {loading ? (
            <div className="grid place-items-center h-64 text-muted-foreground">
              <Loader2 className="size-6 animate-spin" />
            </div>
          ) : items.length === 0 ? (
            <div className="grid place-items-center h-64 text-muted-foreground text-sm">
              No media yet. Upload your first file.
            </div>
          ) : (
            <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
              {items.map((item) => (
                <div
                  key={item.id}
                  onClick={() => setSelected(item)}
                  className={`group relative rounded-xl overflow-hidden border-2 cursor-pointer transition-all ${
                    selected?.id === item.id ? "border-[var(--brand-royal)] ring-2 ring-[var(--brand-royal)]/30" : "border-border hover:border-[var(--brand-royal)]/40"
                  }`}
                >
                  <div className="aspect-square bg-muted grid place-items-center relative">
                    {item.type === "image" ? (
                      // eslint-disable-next-line @next/next/no-img-element
                      <img src={item.url} alt={item.altText || item.originalName} className="size-full object-cover" />
                    ) : item.type === "video" ? (
                      <video src={item.url} className="size-full object-cover" />
                    ) : (
                      <FileText className="size-10 text-muted-foreground" />
                    )}
                    {selected?.id === item.id && (
                      <div className="absolute top-1.5 right-1.5 grid place-items-center size-6 rounded-full bg-[var(--brand-royal)] text-white">
                        <Check className="size-3.5" />
                      </div>
                    )}
                    <button
                      onClick={(e) => { e.stopPropagation(); handleDelete(item.id); }}
                      className="absolute bottom-1.5 right-1.5 grid place-items-center size-7 rounded-md bg-black/60 text-white opacity-0 group-hover:opacity-100 hover:bg-destructive transition-colors"
                    >
                      <Trash2 className="size-3.5" />
                    </button>
                  </div>
                  <div className="p-2 bg-background">
                    <div className="text-xs font-medium truncate">{item.originalName}</div>
                    <div className="text-[10px] text-muted-foreground flex items-center gap-1">
                      {item.type === "image" ? <ImageIcon className="size-2.5" /> : item.type === "video" ? <Video className="size-2.5" /> : <FileText className="size-2.5" />}
                      {(item.size / 1024).toFixed(0)} KB
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>

        <div className="flex items-center justify-between gap-3 pt-3 border-t">
          <div className="text-sm text-muted-foreground truncate">
            {selected ? `Selected: ${selected.originalName}` : "No file selected"}
          </div>
          <div className="flex gap-2">
            <Button variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
            <Button onClick={confirmSelect} disabled={!selected} className="brand-gradient text-white">
              Select File
            </Button>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

/** A trigger button + picker combo for forms. */
export function MediaPickerButton({
  value,
  onChange,
  accept = "image",
  label = "Choose Media",
}: {
  value?: string | null;
  onChange: (url: string | null) => void;
  accept?: "image" | "video" | "all";
  label?: string;
}) {
  const [open, setOpen] = React.useState(false);
  return (
    <>
      <div className="flex items-center gap-3">
        {value && accept !== "video" && (
          // eslint-disable-next-line @next/next/no-img-element
          <img src={value} alt="" className="size-14 rounded-lg object-cover border border-border" />
        )}
        {value && accept === "video" && (
          <video src={value} className="size-14 rounded-lg object-cover border border-border" />
        )}
        <div className="flex flex-col gap-1.5">
          <Button type="button" variant="outline" size="sm" onClick={() => setOpen(true)}>
            <Upload className="size-3.5 mr-1.5" /> {value ? "Change" : label}
          </Button>
          {value && (
            <Button type="button" variant="ghost" size="sm" className="text-destructive h-7" onClick={() => onChange(null)}>
              Remove
            </Button>
          )}
        </div>
      </div>
      <MediaPicker open={open} onOpenChange={setOpen} accept={accept} onSelect={(item) => onChange(item.url)} />
    </>
  );
}
