"use client";

/* eslint-disable @next/next/no-img-element */

import { useEffect, useMemo, useRef, useState, type ChangeEvent } from "react";
import type { MediaFile } from "@/lib/admin/media";

type SortKey = "date" | "name" | "size";
type FilterKey = "all" | "images" | "pdf";

type ApiResponse = {
  message?: string;
  files?: MediaFile[];
};

function formatBytes(size: number) {
  if (size < 1024) return `${size} B`;
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
  return `${(size / 1024 / 1024).toFixed(1)} MB`;
}

function sortFiles(files: MediaFile[], sort: SortKey) {
  return [...files].sort((left, right) => {
    if (sort === "name") return left.name.localeCompare(right.name);
    if (sort === "size") return right.size - left.size;
    return right.uploadedAt.localeCompare(left.uploadedAt);
  });
}

export default function MediaManager({ initialFiles }: { initialFiles: MediaFile[] }) {
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [files, setFiles] = useState(initialFiles);
  const [filter, setFilter] = useState<FilterKey>("all");
  const [sort, setSort] = useState<SortKey>("date");
  const [query, setQuery] = useState("");
  const [toast, setToast] = useState("");
  const [error, setError] = useState("");
  const [pending, setPending] = useState(false);
  const [preview, setPreview] = useState<MediaFile | null>(null);
  const [zoom, setZoom] = useState(1);

  useEffect(() => {
    function closeOnEscape(event: KeyboardEvent) {
      if (event.key === "Escape") {
        setPreview(null);
        setZoom(1);
      }
    }

    window.addEventListener("keydown", closeOnEscape);
    return () => window.removeEventListener("keydown", closeOnEscape);
  }, []);

  const visibleFiles = useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();
    const filtered = files.filter((file) => {
      if (filter === "images" && !file.isImage) return false;
      if (filter === "pdf" && !file.isPdf) return false;
      if (!normalizedQuery) return true;
      return file.name.toLowerCase().includes(normalizedQuery) || file.extension.toLowerCase().includes(normalizedQuery);
    });
    return sortFiles(filtered, sort);
  }, [files, filter, query, sort]);

  async function upload(event: ChangeEvent<HTMLInputElement>) {
    const file = event.currentTarget.files?.[0];
    if (!file) return;

    setPending(true);
    setToast("");
    setError("");

    const form = new FormData();
    form.set("file", file);

    try {
      const response = await fetch("/api/admin/media", { method: "POST", body: form });
      const result = await response.json() as ApiResponse;
      if (!response.ok) throw new Error(result.message ?? "Upload fehlgeschlagen.");
      if (result.files) setFiles(result.files);
      setToast(result.message ?? "Datei erfolgreich hochgeladen.");
      if (fileInputRef.current) fileInputRef.current.value = "";
    } catch (err) {
      setError(err instanceof Error ? err.message : "Upload fehlgeschlagen.");
    } finally {
      setPending(false);
    }
  }

  async function refresh() {
    const response = await fetch("/api/admin/media", { method: "GET" });
    const result = await response.json() as ApiResponse;
    if (response.ok && result.files) setFiles(result.files);
  }

  async function remove(file: MediaFile) {
    if (!window.confirm(`Datei wirklich löschen?\n\n${file.name}`)) return;
    setToast("");
    setError("");

    try {
      const response = await fetch("/api/admin/media", {
        method: "DELETE",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name: file.name }),
      });
      const result = await response.json() as ApiResponse;
      if (!response.ok) throw new Error(result.message ?? "Datei konnte nicht gelöscht werden.");
      if (result.files) setFiles(result.files);
      setToast(result.message ?? "Datei gelöscht.");
    } catch (err) {
      setError(err instanceof Error ? err.message : "Datei konnte nicht gelöscht werden.");
    }
  }

  async function copyUrl(file: MediaFile) {
    try {
      await navigator.clipboard.writeText(file.url);
      setToast("Relative URL wurde kopiert.");
      setError("");
    } catch {
      setError("URL konnte nicht kopiert werden.");
    }
  }

  function openPreview(file: MediaFile) {
    if (file.isImage) {
      setPreview(file);
      setZoom(1);
      return;
    }

    window.open(file.url, "_blank", "noopener,noreferrer");
  }

  return (
    <>
      {toast && <p className="success admin-message">{toast}</p>}
      {error && <p className="error admin-message">{error}</p>}

      <section className="admin-card media-toolbar">
        <label>
          Datei hochladen
          <input ref={fileInputRef} type="file" accept="image/jpeg,image/png,image/webp,application/pdf" onChange={upload} disabled={pending} />
        </label>
        <label>
          Suche
          <input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Dateiname oder Typ" />
        </label>
        <label>
          Filter
          <select value={filter} onChange={(event) => setFilter(event.target.value as FilterKey)}>
            <option value="all">Alle</option>
            <option value="images">Bilder</option>
            <option value="pdf">PDF</option>
          </select>
        </label>
        <label>
          Sortierung
          <select value={sort} onChange={(event) => setSort(event.target.value as SortKey)}>
            <option value="date">Datum</option>
            <option value="name">Name</option>
            <option value="size">Größe</option>
          </select>
        </label>
        <button className="button light" type="button" onClick={refresh}>Aktualisieren</button>
      </section>

      <section className="admin-card">
        <h2>Uploads</h2>
        {visibleFiles.length === 0 ? (
          <div className="media-empty">
            <h3>Noch keine Medien vorhanden</h3>
            <p>Hochgeladene Bilder und PDF-Dateien erscheinen hier mit Vorschau, Metadaten und Aktionen.</p>
          </div>
        ) : (
          <div className="media-card-grid">
            {visibleFiles.map((file) => (
              <article key={file.name} className="media-card">
                <button className="media-card-preview" type="button" onClick={() => openPreview(file)}>
                  {file.isImage ? <img src={file.url} alt={file.name} /> : <span className="pdf-icon">PDF</span>}
                </button>
                <div className="media-card-body">
                  <h3 title={file.name}>{file.name}</h3>
                  <dl className="media-meta">
                    <div><dt>Typ</dt><dd>{file.extension}</dd></div>
                    <div><dt>Größe</dt><dd>{formatBytes(file.size)}</dd></div>
                    <div><dt>Upload</dt><dd>{new Date(file.uploadedAt).toLocaleString("de-DE")}</dd></div>
                  </dl>
                  <div className="media-actions">
                    <button type="button" onClick={() => openPreview(file)}>Vorschau</button>
                    <a href={file.url} download={file.name}>Download</a>
                    <button type="button" onClick={() => copyUrl(file)}>URL kopieren</button>
                    <button type="button" className="danger" onClick={() => remove(file)}>Löschen</button>
                  </div>
                </div>
              </article>
            ))}
          </div>
        )}
      </section>

      {preview && (
        <div className="lightbox" role="dialog" aria-modal="true" aria-label={`Vorschau ${preview.name}`}>
          <div className="lightbox-toolbar">
            <strong>{preview.name}</strong>
            <div>
              <button type="button" onClick={() => setZoom((value) => Math.max(0.5, value - 0.25))}>Zoom -</button>
              <button type="button" onClick={() => setZoom((value) => Math.min(3, value + 0.25))}>Zoom +</button>
              <button type="button" onClick={() => { setPreview(null); setZoom(1); }}>Schließen</button>
            </div>
          </div>
          <button className="lightbox-backdrop" type="button" aria-label="Vorschau schließen" onClick={() => { setPreview(null); setZoom(1); }} />
          <div className="lightbox-stage">
            <img src={preview.url} alt={preview.name} style={{ transform: `scale(${zoom})` }} />
          </div>
        </div>
      )}
    </>
  );
}
