"use client";

import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
  Upload,
  Search,
  ImageIcon,
  Film,
  Music,
  FileText,
  Link2,
  Trash2,
  Loader2,
  Copy,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  deleteMediaLibraryItem,
  getMediaLibrary,
  parseMediaLibraryList,
  registerMediaLibrary,
  type MediaLibraryItem,
  uploadMediaLibraryFile,
} from "@/service/media-library";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Label } from "@/components/ui/label";

const getFileIcon = (type: string) => {
  switch (type) {
    case "video":
      return <Film className="h-8 w-8 text-purple-500" />;
    case "audio":
      return <Music className="h-8 w-8 text-green-500" />;
    case "document":
      return <FileText className="h-8 w-8 text-amber-600" />;
    default:
      return <ImageIcon className="h-8 w-8 text-blue-500" />;
  }
};

function looksLikeImageUrl(url: string): boolean {
  const path = url.split("?")[0].split("#")[0].toLowerCase();
  return /\.(jpe?g|png|gif|webp|svg|bmp|avif)$/i.test(path);
}

function isDisplayableImage(file: MediaLibraryItem): boolean {
  return file.file_category === "image" || looksLikeImageUrl(file.public_url);
}

function LibraryMediaPreview({ file }: { file: MediaLibraryItem }) {
  const [broken, setBroken] = useState(false);
  const showImg = isDisplayableImage(file) && !broken && Boolean(file.public_url?.trim());

  if (showImg) {
    return (
      // eslint-disable-next-line @next/next/no-img-element -- dynamic API/MinIO URLs
      <img
        src={file.public_url}
        alt={file.original_filename || "Preview"}
        className="h-full w-full object-cover"
        loading="lazy"
        decoding="async"
        onError={() => setBroken(true)}
      />
    );
  }

  return (
    <div className="flex h-full w-full items-center justify-center bg-slate-100">
      {getFileIcon(file.file_category)}
    </div>
  );
}

const getBadgeStyle = (type: string) => {
  switch (type) {
    case "video":
      return "bg-purple-100 text-purple-600";
    case "audio":
      return "bg-green-100 text-green-600";
    case "document":
      return "bg-amber-100 text-amber-800";
    default:
      return "bg-blue-100 text-blue-600";
  }
};

function formatBytes(n: number | null | undefined): string {
  if (n == null || Number.isNaN(n)) return "—";
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  return `${(n / (1024 * 1024)).toFixed(1)} MB`;
}

function formatDate(iso: string): string {
  try {
    return new Date(iso).toLocaleDateString(undefined, {
      year: "numeric",
      month: "short",
      day: "numeric",
    });
  } catch {
    return iso;
  }
}

const SOURCE_OPTIONS = [
  { value: "all", label: "Semua sumber" },
  { value: "article_file", label: "Artikel" },
  { value: "cms", label: "Content Website" },
  { value: "upload", label: "Upload langsung" },
];

export default function MediaLibrary() {
  const [search, setSearch] = useState("");
  const [sourceFilter, setSourceFilter] = useState("all");
  const [page, setPage] = useState(1);
  const [items, setItems] = useState<MediaLibraryItem[]>([]);
  const [totalPage, setTotalPage] = useState(1);
  const [totalCount, setTotalCount] = useState<number | null>(null);
  const [loading, setLoading] = useState(true);
  const [uploading, setUploading] = useState(false);
  const [registerUrl, setRegisterUrl] = useState("");
  const [registerLabel, setRegisterLabel] = useState("");
  const [registering, setRegistering] = useState(false);
  const fileRef = useRef<HTMLInputElement>(null);

  const load = useCallback(async () => {
    setLoading(true);
    const res = await getMediaLibrary({
      page,
      limit: 24,
      q: search.trim() || undefined,
      source_type: sourceFilter === "all" ? undefined : sourceFilter,
    });
    const { items: rows, meta } = parseMediaLibraryList(res);
    setItems(rows);
    setTotalPage(Math.max(1, meta?.totalPage ?? 1));
    if (typeof meta?.count === "number") setTotalCount(meta.count);
    setLoading(false);
  }, [page, search, sourceFilter]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect -- fetch on deps
    void load();
  }, [load]);

  const stats = useMemo(() => {
    const images = items.filter((i) => i.file_category === "image").length;
    const videos = items.filter((i) => i.file_category === "video").length;
    const audio = items.filter((i) => i.file_category === "audio").length;
    const docs = items.filter((i) => i.file_category === "document").length;
    return [
      { title: "Total (filter)", value: totalCount ?? "—" },
      { title: "Gambar (halaman)", value: images },
      { title: "Video (halaman)", value: videos },
      { title: "Audio/Dokumen (halaman)", value: audio + docs },
    ];
  }, [items, totalCount]);

  const copyLink = async (url: string) => {
    try {
      await navigator.clipboard.writeText(url);
    } catch {
      window.prompt("Salin URL:", url);
    }
  };

  const onSelectFiles = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files?.length) return;
    setUploading(true);
    for (let i = 0; i < files.length; i++) {
      const fd = new FormData();
      fd.append("file", files[i]);
      await uploadMediaLibraryFile(fd);
    }
    setUploading(false);
    e.target.value = "";
    setPage(1);
    await load();
  };

  const onRegisterManual = async () => {
    const url = registerUrl.trim();
    if (!url) return;
    setRegistering(true);
    await registerMediaLibrary({
      public_url: url,
      source_type: "upload",
      source_label: registerLabel.trim() || "manual_register",
    });
    setRegisterUrl("");
    setRegisterLabel("");
    setRegistering(false);
    setPage(1);
    await load();
  };

  const onDelete = async (id: number) => {
    if (!confirm("Hapus entri dari Media Library? (file di storage tidak dihapus)")) return;
    await deleteMediaLibraryItem(id);
    await load();
  };

  return (
    <div className="space-y-8">
      <div>
        <h1 className="text-2xl font-semibold">Media Library</h1>
        <p className="text-sm text-muted-foreground">
          Katalog URL media dari artikel, Content Website, dan upload admin. File fisik
          tetap satu; yang disimpan di sini adalah tautan publik untuk pencarian dan salin
          cepat.
        </p>
      </div>

      <Card className="overflow-hidden rounded-2xl p-0">
        <CardContent className="p-0">
          <div className="space-y-4 bg-gradient-to-r from-[#966314] to-[#b07c18] p-8 text-center text-white">
            <Upload className="mx-auto h-10 w-10" />
            <h2 className="text-lg font-semibold">Upload ke Media Library</h2>
            <p className="text-sm text-white/90">
              File disimpan di MinIO (prefix cms/media-library) dan URL viewer otomatis
              didaftarkan di tabel ini.
            </p>
            <input
              ref={fileRef}
              type="file"
              className="hidden"
              accept=".jpg,.jpeg,.png,.gif,.webp,.svg,.mp4,.webm,.mov,.mp3,.wav,.ogg,.m4a,.pdf,.doc,.docx,.txt,.csv"
              multiple
              onChange={(e) => void onSelectFiles(e)}
            />
            <Button
              type="button"
              className="bg-white text-[#966314] hover:bg-white/90"
              disabled={uploading}
              onClick={() => fileRef.current?.click()}
            >
              {uploading ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  Mengunggah…
                </>
              ) : (
                "Pilih file"
              )}
            </Button>
            <p className="text-xs text-white/80">
              Gambar, video, audio, PDF/DOC/TXT (satu file per request batch di atas)
            </p>
          </div>
        </CardContent>
      </Card>

      <Card className="rounded-xl border-dashed p-4">
        <div className="flex flex-col gap-3 md:flex-row md:items-end">
          <div className="flex-1 space-y-2">
            <Label>Daftarkan URL yang sudah ada</Label>
            <Input
              placeholder="https://… (mis. dari artikel atau CMS)"
              value={registerUrl}
              onChange={(e) => setRegisterUrl(e.target.value)}
            />
          </div>
          <div className="w-full space-y-2 md:w-56">
            <Label>Label (opsional)</Label>
            <Input
              placeholder="mis. campaign_q1"
              value={registerLabel}
              onChange={(e) => setRegisterLabel(e.target.value)}
            />
          </div>
          <Button
            type="button"
            variant="secondary"
            disabled={registering || !registerUrl.trim()}
            onClick={() => void onRegisterManual()}
          >
            {registering ? <Loader2 className="h-4 w-4 animate-spin" /> : <Link2 className="h-4 w-4" />}
            <span className="ml-2">Simpan ke library</span>
          </Button>
        </div>
      </Card>

      <div className="grid grid-cols-2 gap-4 md:grid-cols-4">
        {stats.map((item, i) => (
          <Card key={i} className="rounded-xl shadow-sm">
            <CardContent className="p-5">
              <p className="text-2xl font-semibold">{item.value}</p>
              <p className="text-sm text-muted-foreground">{item.title}</p>
            </CardContent>
          </Card>
        ))}
      </div>

      <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
        <div className="relative w-full md:max-w-md">
          <Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
          <Input
            placeholder="Cari nama file atau URL…"
            className="pl-9"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                setPage(1);
                void load();
              }
            }}
          />
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <Select value={sourceFilter} onValueChange={(v) => { setSourceFilter(v); setPage(1); }}>
            <SelectTrigger className="w-[200px]">
              <SelectValue placeholder="Sumber" />
            </SelectTrigger>
            <SelectContent>
              {SOURCE_OPTIONS.map((o) => (
                <SelectItem key={o.value} value={o.value}>
                  {o.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <Button variant="outline" type="button" onClick={() => void load()}>
            Refresh
          </Button>
        </div>
      </div>

      {loading ? (
        <div className="flex justify-center py-16 text-muted-foreground">
          <Loader2 className="h-8 w-8 animate-spin" />
        </div>
      ) : items.length === 0 ? (
        <p className="py-12 text-center text-muted-foreground">Belum ada media.</p>
      ) : (
        <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
          {items.map((file) => (
            <Card
              key={file.id}
              className="overflow-hidden rounded-2xl shadow-sm transition hover:shadow-md"
            >
              <div className="relative h-36 w-full overflow-hidden bg-slate-100">
                <LibraryMediaPreview file={file} />
              </div>

              <CardContent className="space-y-2 p-4">
                <p className="truncate text-sm font-medium" title={file.original_filename ?? ""}>
                  {file.original_filename || "—"}
                </p>

                <div className="flex items-center justify-between text-xs text-muted-foreground">
                  <Badge className={getBadgeStyle(file.file_category)}>
                    {file.file_category}
                  </Badge>
                  <span>{formatBytes(file.size_bytes ?? undefined)}</span>
                </div>

                <p className="text-xs text-muted-foreground">
                  {file.source_type}
                  {file.source_label ? ` · ${file.source_label}` : ""}
                </p>
                <p className="text-xs text-muted-foreground">{formatDate(file.created_at)}</p>

                <div className="flex flex-wrap gap-2 pt-1">
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    className="h-8 flex-1"
                    onClick={() => void copyLink(file.public_url)}
                  >
                    <Copy className="mr-1 h-3.5 w-3.5" />
                    Salin URL
                  </Button>
                  <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    className="h-8 text-destructive"
                    onClick={() => void onDelete(file.id)}
                  >
                    <Trash2 className="h-3.5 w-3.5" />
                  </Button>
                </div>
              </CardContent>
            </Card>
          ))}
        </div>
      )}

      {totalPage > 1 ? (
        <div className="flex justify-center gap-2">
          <Button
            variant="outline"
            size="sm"
            disabled={page <= 1}
            onClick={() => setPage((p) => Math.max(1, p - 1))}
          >
            Sebelumnya
          </Button>
          <span className="flex items-center px-2 text-sm text-muted-foreground">
            Halaman {page} / {totalPage}
          </span>
          <Button
            variant="outline"
            size="sm"
            disabled={page >= totalPage}
            onClick={() => setPage((p) => p + 1)}
          >
            Berikutnya
          </Button>
        </div>
      ) : null}
    </div>
  );
}
