"use client";

import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import { Copy, Loader2, Trash2, Upload, ZoomIn } from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Slider } from "@/components/ui/slider";
import type { CmsMedia } from "@/lib/cms/types";
import { cn } from "@/lib/utils";

export function CmsMediaLibrary() {
  const [items, setItems] = useState<CmsMedia[]>([]);
  const [loading, setLoading] = useState(true);
  const [uploading, setUploading] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const [preview, setPreview] = useState<CmsMedia | null>(null);
  const [altText, setAltText] = useState("");
  const [focal, setFocal] = useState<[number, number]>([0.5, 0.5]);
  const inputRef = useRef<HTMLInputElement>(null);

  async function load() {
    const res = await fetch("/api/admin/cms/media");
    if (!res.ok) return;
    const data = (await res.json()) as { items: CmsMedia[] };
    setItems(data.items ?? []);
  }

  useEffect(() => {
    let cancelled = false;
    async function loadInitial() {
      const res = await fetch("/api/admin/cms/media");
      if (!res.ok) {
        if (!cancelled) setLoading(false);
        return;
      }
      const data = (await res.json()) as { items: CmsMedia[] };
      if (cancelled) return;
      setItems(data.items ?? []);
      setLoading(false);
    }
    void loadInitial().catch(() => {
      if (!cancelled) setLoading(false);
    });
    return () => {
      cancelled = true;
    };
  }, []);

  async function uploadFile(file: File) {
    setUploading(true);
    const fd = new FormData();
    fd.append("file", file);
    fd.append("altText", file.name.replace(/\.[^.]+$/, "").replace(/[-_]/g, " "));
    const res = await fetch("/api/admin/cms/media", { method: "POST", body: fd });
    setUploading(false);
    if (!res.ok) {
      const err = await res.json().catch(() => ({}));
      toast.error(typeof err.error === "string" ? err.error : "Upload failed.");
      return;
    }
    toast.success("Image optimized and uploaded.");
    await load();
  }

  async function onFiles(files: FileList | null) {
    if (!files?.length) return;
    for (const file of files) {
      await uploadFile(file);
    }
  }

  async function saveMeta() {
    if (!preview) return;
    const res = await fetch("/api/admin/cms/media", {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ id: preview.id, altText, focalX: focal[0], focalY: focal[1] }),
    });
    if (!res.ok) {
      toast.error("Could not save metadata.");
      return;
    }
    toast.success("Saved.");
    setPreview(null);
    await load();
  }

  async function deleteItem(id: string) {
    if (!confirm("Delete this image permanently?")) return;
    const res = await fetch(`/api/admin/cms/media?id=${encodeURIComponent(id)}`, { method: "DELETE" });
    if (!res.ok) {
      toast.error("Delete failed.");
      return;
    }
    toast.success("Deleted.");
    await load();
  }

  function openPreview(item: CmsMedia) {
    setPreview(item);
    setAltText(item.altText ?? "");
    setFocal([item.focalX, item.focalY]);
  }

  return (
    <div className="space-y-6">
      <div
        className={cn(
          "rounded-2xl border-2 border-dashed p-10 text-center transition-colors",
          dragOver ? "border-primary bg-primary/5" : "border-white/15 bg-white/[0.02]",
        )}
        onDragOver={(e) => {
          e.preventDefault();
          setDragOver(true);
        }}
        onDragLeave={() => setDragOver(false)}
        onDrop={(e) => {
          e.preventDefault();
          setDragOver(false);
          void onFiles(e.dataTransfer.files);
        }}
      >
        <Upload className="text-muted-foreground mx-auto size-10" />
        <p className="mt-3 font-medium">Drag & drop images here</p>
        <p className="text-muted-foreground mt-1 text-sm">Max 5 MB. Auto-compressed to WebP (max 1600px wide).</p>
        <input
          ref={inputRef}
          type="file"
          accept="image/jpeg,image/png,image/webp,image/gif,image/svg+xml"
          multiple
          className="hidden"
          onChange={(e) => void onFiles(e.target.files)}
        />
        <Button
          type="button"
          className="mt-4 gap-2"
          disabled={uploading}
          onClick={() => inputRef.current?.click()}
        >
          {uploading ? <Loader2 className="size-4 animate-spin" /> : <Upload className="size-4" />}
          Upload images
        </Button>
      </div>

      {loading ? (
        <div className="text-muted-foreground flex items-center gap-2 py-12">
          <Loader2 className="size-5 animate-spin text-primary" /> Loading media…
        </div>
      ) : items.length === 0 ? (
        <p className="text-muted-foreground py-8 text-center">No media uploaded yet.</p>
      ) : (
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
          {items.map((item) => (
            <div
              key={item.id}
              className="group overflow-hidden rounded-xl border border-white/10 bg-white/[0.03]"
            >
              <div className="relative aspect-[4/3] bg-black/40">
                {item.mimeType === "image/svg+xml" ? (
                  // eslint-disable-next-line @next/next/no-img-element
                  <img src={item.url} alt={item.altText ?? ""} className="size-full object-contain p-4" />
                ) : (
                  <Image
                    src={item.url}
                    alt={item.altText ?? item.filename}
                    fill
                    className="object-cover"
                    sizes="(max-width: 768px) 50vw, 25vw"
                    loading="lazy"
                  />
                )}
                <div className="absolute inset-0 flex items-end justify-end gap-1 bg-gradient-to-t from-black/70 to-transparent p-2 opacity-0 transition-opacity group-hover:opacity-100">
                  <Button type="button" size="icon" variant="secondary" className="size-8" onClick={() => openPreview(item)}>
                    <ZoomIn className="size-4" />
                  </Button>
                  <Button
                    type="button"
                    size="icon"
                    variant="secondary"
                    className="size-8"
                    onClick={() => void navigator.clipboard.writeText(item.url).then(() => toast.success("URL copied."))}
                  >
                    <Copy className="size-4" />
                  </Button>
                  <Button type="button" size="icon" variant="destructive" className="size-8" onClick={() => void deleteItem(item.id)}>
                    <Trash2 className="size-4" />
                  </Button>
                </div>
              </div>
              <div className="space-y-1 p-3">
                <p className="truncate text-xs font-medium">{item.filename}</p>
                <p className="text-muted-foreground text-xs">
                  {(item.sizeBytes / 1024).toFixed(0)} KB
                  {item.width ? ` · ${item.width}×${item.height}` : ""}
                  {item.variants.length ? ` · ${item.variants.length} sizes` : ""}
                </p>
                {item.altText ? (
                  <p className="text-muted-foreground truncate text-xs">Alt: {item.altText}</p>
                ) : (
                  <p className="text-amber-400/80 text-xs">Missing alt text</p>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      <Dialog open={!!preview} onOpenChange={(open) => !open && setPreview(null)}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>Image details</DialogTitle>
          </DialogHeader>
          {preview ? (
            <div className="space-y-4">
              <div className="relative aspect-video overflow-hidden rounded-lg bg-black">
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img
                  src={preview.url}
                  alt={altText}
                  className="size-full object-cover"
                  style={{ objectPosition: `${focal[0] * 100}% ${focal[1] * 100}%` }}
                />
              </div>
              <div className="space-y-2">
                <Label htmlFor="alt">Alt text (SEO)</Label>
                <Input id="alt" value={altText} onChange={(e) => setAltText(e.target.value)} placeholder="Describe the image" />
              </div>
              <div className="space-y-2">
                <Label>Focal point X</Label>
                <Slider
                  value={[focal[0]]}
                  min={0}
                  max={1}
                  step={0.01}
                  onValueChange={(v) => {
                    const x = Array.isArray(v) ? v[0] : v;
                    setFocal([typeof x === "number" ? x : 0.5, focal[1]]);
                  }}
                />
              </div>
              <div className="space-y-2">
                <Label>Focal point Y</Label>
                <Slider
                  value={[focal[1]]}
                  min={0}
                  max={1}
                  step={0.01}
                  onValueChange={(v) => {
                    const y = Array.isArray(v) ? v[0] : v;
                    setFocal([focal[0], typeof y === "number" ? y : 0.5]);
                  }}
                />
              </div>
              <Button type="button" className="w-full" onClick={() => void saveMeta()}>
                Save metadata
              </Button>
            </div>
          ) : null}
        </DialogContent>
      </Dialog>
    </div>
  );
}
