"use client";
import { useEffect, useState, useTransition } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { Check, FolderHeart, Pencil, Type, X } from "lucide-react";
import { reorderCollection, renameCollection } from "@/app/actions/collections";
import { thumbUrl, collectionCoverUrl } from "@/lib/assetUrls";
import { cn } from "@/lib/utils";
import { CollectionSelectionProvider, useCollectionSelection } from "./CollectionSelectionProvider";
import { CollectionCoverEditor } from "./CollectionCoverEditor";

interface CollectionListItem {
  id: number;
  name: string;
  slug: string;
  description: string | null;
  cover_thumb: string | null;
  first_thumb: string | null;
  count: number;
  coverPortraitPath: string | null;
  coverPortraitZoom: number;
  coverPortraitOffsetX: number;
  coverPortraitOffsetY: number;
  coverLandscapePath: string | null;
  coverLandscapeZoom: number;
  coverLandscapeOffsetX: number;
  coverLandscapeOffsetY: number;
}

const PHI = 1.618;
// Canonical frame widths used by the cover editor preview. The card
// reproduces editor offsets via `cqw` so a 50px offset on a 583px-wide
// editor preview scales correctly on a 430px-wide grid card.
const FRAME_H = 360;
const CANONICAL_PORTRAIT_W = Math.round(FRAME_H / PHI);
const CANONICAL_LANDSCAPE_W = Math.round(FRAME_H * PHI);

export function ReorderableCollectionsIndex({
  items,
  view = "landscape",
}: {
  items: CollectionListItem[];
  view?: "portrait" | "landscape";
}) {
  return (
    <CollectionSelectionProvider>
      <Inner items={items} view={view} />
    </CollectionSelectionProvider>
  );
}

function Inner({ items: initial, view }: { items: CollectionListItem[]; view: "portrait" | "landscape" }) {
  const sel = useCollectionSelection();
  const [items, setItems] = useState(initial);
  const [draggingId, setDraggingId] = useState<number | null>(null);
  const [dropBeforeId, setDropBeforeId] = useState<number | "end" | null>(null);
  const [editing, setEditing] = useState<CollectionListItem | null>(null);
  const [renamingId, setRenamingId] = useState<number | null>(null);
  const [draftName, setDraftName] = useState("");
  const [renamePending, setRenamePending] = useState(false);
  const [, start] = useTransition();
  const router = useRouter();

  function startRename(c: CollectionListItem) {
    setRenamingId(c.id);
    setDraftName(c.name);
  }
  function cancelRename() {
    setRenamingId(null);
    setDraftName("");
  }
  async function commitRename(c: CollectionListItem) {
    const next = draftName.trim();
    if (!next || next === c.name) { cancelRename(); return; }
    setRenamePending(true);
    await renameCollection(c.id, next);
    setRenamePending(false);
    setRenamingId(null);
    setDraftName("");
    router.refresh();
  }

  // Reconcile when the prop changes (after server refresh). Includes
  // cover-art fields so save-and-router.refresh() picks up new
  // transforms even when the row order is unchanged. Runs in an effect
  // (not during render) so we never call setState mid-render.
  useEffect(() => {
    setItems(initial);
  }, [initial]);

  function onDragStart(id: number, e: React.DragEvent) {
    setDraggingId(id);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", String(id));
  }

  function onDragOverCard(id: number, e: React.DragEvent) {
    if (draggingId == null) return;
    e.preventDefault();
    setDropBeforeId(id);
  }

  function onDragOverEnd(e: React.DragEvent) {
    if (draggingId == null) return;
    e.preventDefault();
    setDropBeforeId("end");
  }

  function commitDrop() {
    if (draggingId == null || dropBeforeId == null) {
      setDraggingId(null);
      setDropBeforeId(null);
      return;
    }
    const movedId = draggingId;
    const beforeId = dropBeforeId === "end" ? null : dropBeforeId;
    if (movedId === beforeId) {
      setDraggingId(null);
      setDropBeforeId(null);
      return;
    }
    setItems((cur) => {
      const fromIdx = cur.findIndex((x) => x.id === movedId);
      if (fromIdx === -1) return cur;
      const moved = cur[fromIdx];
      const without = [...cur.slice(0, fromIdx), ...cur.slice(fromIdx + 1)];
      let toIdx = beforeId == null ? without.length : without.findIndex((x) => x.id === beforeId);
      if (toIdx === -1) toIdx = without.length;
      return [...without.slice(0, toIdx), moved, ...without.slice(toIdx)];
    });
    setDraggingId(null);
    setDropBeforeId(null);
    start(async () => {
      try {
        await reorderCollection(movedId, beforeId);
        router.refresh();
      } catch (err) {
        // Revert the optimistic reorder so the UI doesn't lie about
        // the persisted order.
        console.error("[reorderCollection] failed:", err);
        setItems(initial);
      }
    });
  }

  function onDragEnd() {
    setDraggingId(null);
    setDropBeforeId(null);
  }

  const isLandscape = view === "landscape";
  const gridCls = isLandscape
    ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
    : "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 gap-4";

  return (
    <>
      <div
        key={view}
        className={cn("fade-in", gridCls)}
        onDragOver={(e) => { if (draggingId != null) e.preventDefault(); }}
        onDrop={commitDrop}
        onDragEnd={onDragEnd}
      >
        {items.map((c) => {
          const customPath = isLandscape ? c.coverLandscapePath : c.coverPortraitPath;
          const customZoom = isLandscape ? c.coverLandscapeZoom : c.coverPortraitZoom;
          const customOffsetX = isLandscape ? c.coverLandscapeOffsetX : c.coverPortraitOffsetX;
          const customOffsetY = isLandscape ? c.coverLandscapeOffsetY : c.coverPortraitOffsetY;
          const fallbackThumb = c.cover_thumb ?? c.first_thumb;
          const selected = sel.has(c.id);
          const anySelected = sel.ids.size > 0;
          return (
            <div
              key={c.id}
              draggable={renamingId !== c.id}
              onDragStart={(e) => onDragStart(c.id, e)}
              onDragOver={(e) => onDragOverCard(c.id, e)}
              onDragEnd={onDragEnd}
              className={cn(
                "relative group/drag",
                draggingId === c.id && "opacity-40",
                dropBeforeId === c.id && "ring-2 ring-[var(--color-cyan)] ring-offset-2 ring-offset-[var(--color-bg-0)] rounded-2xl",
                selected && "ring-2 ring-[var(--color-cyan)] shadow-[var(--shadow-glow-cyan)] rounded-2xl",
                anySelected && !selected && "opacity-70 hover:opacity-100",
              )}
            >
              <Link
                href={`/collection/${c.slug}`}
                draggable={false}
                onClick={(e) => {
                  if (anySelected) {
                    e.preventDefault();
                    sel.toggle(c.id);
                  }
                }}
                className="group glass glass-hover rounded-2xl overflow-hidden block"
              >
                <div
                  className="relative bg-[var(--color-bg-1)] overflow-hidden"
                  style={{
                    aspectRatio: isLandscape ? `${PHI} / 1` : `1 / ${PHI}`,
                    containerType: "inline-size",
                  }}
                >
                  {customPath ? (
                    /* eslint-disable-next-line @next/next/no-img-element */
                    <img
                      src={collectionCoverUrl(customPath)}
                      alt=""
                      draggable={false}
                      className="absolute top-1/2 left-1/2 max-w-none origin-center pointer-events-none"
                      style={{
                        transform: `translate(-50%, -50%) translate(${customOffsetX / (isLandscape ? CANONICAL_LANDSCAPE_W : CANONICAL_PORTRAIT_W) * 100}cqw, ${customOffsetY / (isLandscape ? CANONICAL_LANDSCAPE_W : CANONICAL_PORTRAIT_W) * 100}cqw) scale(${customZoom})`,
                        width: "100%",
                        height: "auto",
                      }}
                    />
                  ) : fallbackThumb ? (
                    /* eslint-disable-next-line @next/next/no-img-element */
                    <img
                      src={thumbUrl({ thumbPath: fallbackThumb, code: c.name })}
                      alt=""
                      draggable={false}
                      className="absolute inset-0 w-full h-full object-cover group-hover:scale-[1.02] transition-transform"
                    />
                  ) : (
                    <div className="absolute inset-0 grid place-items-center">
                      <FolderHeart className="w-10 h-10 text-[var(--color-fg-muted)]" />
                    </div>
                  )}
                  <div
                    className="absolute top-3 left-3 text-[10px] uppercase tracking-wider font-mono font-semibold px-2 py-0.5 rounded-full bg-black/80 backdrop-blur-md text-[var(--color-cyan)] shadow-md"
                    style={{
                      border: "1px solid rgba(34,211,238,0.4)",
                      textShadow: "0 1px 2px rgba(0,0,0,0.9)",
                    }}
                  >
                    {c.count} Item{c.count === 1 ? "" : "s"}
                  </div>
                  <button
                    type="button"
                    draggable={false}
                    onMouseDown={(e) => e.stopPropagation()}
                    onClick={(e) => {
                      e.preventDefault();
                      e.stopPropagation();
                      sel.toggle(c.id);
                    }}
                    aria-label={selected ? "Deselect" : "Select"}
                    className={cn(
                      "absolute top-3 right-3 w-8 h-8 rounded-md grid place-items-center transition-all backdrop-blur-md border-2",
                      selected
                        ? "bg-[var(--color-cyan)] border-[var(--color-cyan)] text-black shadow-[var(--shadow-glow-cyan)]"
                        : "bg-black/40 border-white/50 text-transparent",
                      !selected && !anySelected && "opacity-0 group-hover/drag:opacity-100",
                    )}
                  >
                    <Check className="w-4 h-4" strokeWidth={3} />
                  </button>
                  <button
                    type="button"
                    draggable={false}
                    onMouseDown={(e) => e.stopPropagation()}
                    onClick={(e) => {
                      e.preventDefault();
                      e.stopPropagation();
                      setEditing(c);
                    }}
                    aria-label="Edit cover"
                    title="Edit cover"
                    className={cn(
                      "absolute bottom-3 right-3 w-8 h-8 rounded-md grid place-items-center transition-all backdrop-blur-md border-2",
                      "bg-black/60 border-white/30 text-white hover:bg-[var(--color-cyan)]/30 hover:border-[var(--color-cyan)] hover:text-[var(--color-cyan)]",
                      "opacity-0 group-hover/drag:opacity-100",
                    )}
                  >
                    <Pencil className="w-4 h-4" />
                  </button>
                </div>
                <div className="p-3">
                  {renamingId === c.id ? (
                    <div
                      className="flex items-center gap-1 h-7"
                      onClick={(e) => { e.preventDefault(); e.stopPropagation(); }}
                      onMouseDown={(e) => e.stopPropagation()}
                    >
                      <input
                        autoFocus
                        value={draftName}
                        onChange={(e) => setDraftName(e.target.value)}
                        onKeyDown={(e) => {
                          if (e.key === "Enter") { e.preventDefault(); commitRename(c); }
                          if (e.key === "Escape") { e.preventDefault(); cancelRename(); }
                        }}
                        disabled={renamePending}
                        maxLength={120}
                        className="flex-1 min-w-0 h-full glass rounded-md px-2 text-sm outline-none focus:border-[var(--color-cyan)]"
                      />
                      <button
                        type="button"
                        onClick={(e) => { e.preventDefault(); e.stopPropagation(); commitRename(c); }}
                        disabled={renamePending || !draftName.trim() || draftName.trim() === c.name}
                        className="flex items-center justify-center w-6 h-6 rounded bg-[var(--color-cyan)] text-black disabled:opacity-40"
                        title="Save"
                      >
                        <Check className="w-3 h-3" strokeWidth={3} />
                      </button>
                      <button
                        type="button"
                        onClick={(e) => { e.preventDefault(); e.stopPropagation(); cancelRename(); }}
                        disabled={renamePending}
                        className="flex items-center justify-center w-6 h-6 rounded glass text-[var(--color-fg-muted)] hover:text-[var(--color-fg)]"
                        title="Cancel"
                      >
                        <X className="w-3 h-3" />
                      </button>
                    </div>
                  ) : (
                    <div className="flex items-center gap-1.5 h-7 min-w-0">
                      <div className="font-medium truncate flex-1 min-w-0">{c.name}</div>
                      <button
                        type="button"
                        onMouseDown={(e) => e.stopPropagation()}
                        onClick={(e) => { e.preventDefault(); e.stopPropagation(); startRename(c); }}
                        title="Rename"
                        aria-label="Rename collection"
                        className="flex-shrink-0 w-6 h-6 grid place-items-center rounded text-[var(--color-fg-muted)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)] opacity-0 group-hover/drag:opacity-100 transition-opacity"
                      >
                        <Type className="w-3.5 h-3.5" />
                      </button>
                    </div>
                  )}
                  {c.description && (
                    <div className="text-xs text-[var(--color-fg-muted)] truncate mt-0.5">{c.description}</div>
                  )}
                </div>
              </Link>
            </div>
          );
        })}
        <div
          onDragOver={onDragOverEnd}
          className={cn(
            "min-h-[120px] rounded-2xl border-2 border-dashed flex items-center justify-center text-xs text-[var(--color-fg-muted)] transition-colors",
            dropBeforeId === "end"
              ? "border-[var(--color-cyan)] bg-[var(--color-cyan)]/5 text-[var(--color-cyan)]"
              : "border-[var(--color-glass-border)]",
          )}
        >
          {draggingId != null ? "Drop here for end of list" : ""}
        </div>
      </div>

      {editing && (
        <CollectionCoverEditor
          collectionId={editing.id}
          collectionName={editing.name}
          initialSlot={view}
          initial={{
            portrait: {
              path: editing.coverPortraitPath,
              zoom: editing.coverPortraitZoom,
              offsetX: editing.coverPortraitOffsetX,
              offsetY: editing.coverPortraitOffsetY,
            },
            landscape: {
              path: editing.coverLandscapePath,
              zoom: editing.coverLandscapeZoom,
              offsetX: editing.coverLandscapeOffsetX,
              offsetY: editing.coverLandscapeOffsetY,
            },
          }}
          onClose={() => setEditing(null)}
        />
      )}
    </>
  );
}
