"use client";

import { ReactNode, useEffect, useMemo, useRef, useState } from "react";
import { Button } from "@/components/ui/Button";

export interface SortableChapterItem {
  id: number;
  title: string;
  order: number;
}

function sameIds(a: number[], b: number[]) {
  return a.length === b.length && a.every((id, i) => id === b[i]);
}

export function SortableReorderList<T extends { id: number; order: number }>({
  items,
  onApply,
  disabled,
  renderItem,
  handleAriaLabel = "جابجایی",
  applyLabel = "اعمال تغییرات",
  variant = "card",
}: {
  items: T[];
  onApply: (orderedIds: number[]) => Promise<void>;
  disabled?: boolean;
  renderItem: (item: T, index: number) => ReactNode;
  handleAriaLabel?: string;
  applyLabel?: string;
  variant?: "card" | "row";
}) {
  const [ordered, setOrdered] = useState<T[]>([]);
  const [draggingId, setDraggingId] = useState<number | null>(null);
  const [overId, setOverId] = useState<number | null>(null);
  const [saving, setSaving] = useState(false);
  const dragIdRef = useRef<number | null>(null);

  const serverIds = useMemo(
    () => [...items].sort((a, b) => a.order - b.order).map((item) => item.id),
    [items],
  );

  useEffect(() => {
    setOrdered([...items].sort((a, b) => a.order - b.order));
  }, [items]);

  const dirty = !sameIds(
    ordered.map((item) => item.id),
    serverIds,
  );

  const handleDrop = (targetId: number) => {
    const fromId = dragIdRef.current;
    if (fromId === null || fromId === targetId) {
      setDraggingId(null);
      setOverId(null);
      dragIdRef.current = null;
      return;
    }

    const fromIndex = ordered.findIndex((item) => item.id === fromId);
    const toIndex = ordered.findIndex((item) => item.id === targetId);
    if (fromIndex < 0 || toIndex < 0) return;

    const next = [...ordered];
    const [item] = next.splice(fromIndex, 1);
    next.splice(toIndex, 0, item);
    setOrdered(next);
    setDraggingId(null);
    setOverId(null);
    dragIdRef.current = null;
  };

  const applyChanges = async () => {
    setSaving(true);
    try {
      await onApply(ordered.map((item) => item.id));
    } finally {
      setSaving(false);
    }
  };

  if (ordered.length === 0) return null;

  return (
    <div className={variant === "card" ? "space-y-3" : "space-y-1"} aria-busy={saving || undefined}>
      {ordered.map((item, index) => {
        const isDragging = draggingId === item.id;
        const isOver = overId === item.id && draggingId !== item.id;
        const card = variant === "card";

        return (
          <div
            key={item.id}
            className={
              card
                ? `rounded-2xl border bg-white transition-shadow ${
                    isDragging ? "opacity-50" : ""
                  } ${isOver ? "border-primary shadow-md" : "border-[var(--border)]"}`
                : `flex items-center rounded-lg border px-2 py-1.5 text-sm transition-shadow ${
                    isDragging ? "opacity-50" : ""
                  } ${isOver ? "border-primary shadow-sm" : "border-[var(--border)]"}`
            }
            onDragOver={(e) => {
              if (disabled || saving) return;
              e.preventDefault();
              e.stopPropagation();
              setOverId(item.id);
            }}
            onDragLeave={() => {
              if (overId === item.id) setOverId(null);
            }}
            onDrop={(e) => {
              e.preventDefault();
              e.stopPropagation();
              if (!disabled && !saving) handleDrop(item.id);
            }}
          >
            <div className={card ? "flex items-start gap-2 p-1" : "flex min-w-0 flex-1 items-center gap-1"}>
              {!disabled ? (
                <button
                  type="button"
                  draggable={!saving}
                  aria-label={handleAriaLabel}
                  className={
                    card
                      ? "mt-3 cursor-grab rounded-lg px-2 py-3 text-[var(--muted)] hover:bg-slate-100 active:cursor-grabbing"
                      : "cursor-grab rounded px-1 py-1 text-[var(--muted)] hover:bg-slate-100 active:cursor-grabbing"
                  }
                  onDragStart={(e) => {
                    e.stopPropagation();
                    dragIdRef.current = item.id;
                    setDraggingId(item.id);
                    e.dataTransfer.effectAllowed = "move";
                  }}
                  onDragEnd={() => {
                    setDraggingId(null);
                    setOverId(null);
                    dragIdRef.current = null;
                  }}
                >
                  ⠿
                </button>
              ) : null}
              <div className="min-w-0 flex-1">{renderItem(item, index)}</div>
            </div>
          </div>
        );
      })}
      {!disabled && dirty ? (
        <div className="flex justify-end pt-1">
          <Button
            variant="secondary"
            className="!px-3 !py-1 text-xs"
            onClick={() => void applyChanges()}
            disabled={saving}
          >
            {saving ? "در حال ذخیره…" : applyLabel}
          </Button>
        </div>
      ) : null}
    </div>
  );
}

export function SortableChapterList<T extends SortableChapterItem>({
  chapters,
  onReorder,
  disabled,
  renderChapter,
}: {
  chapters: T[];
  onReorder: (orderedIds: number[]) => Promise<void>;
  disabled?: boolean;
  renderChapter: (chapter: T, index: number) => ReactNode;
}) {
  return (
    <SortableReorderList
      items={chapters}
      onApply={onReorder}
      disabled={disabled}
      renderItem={renderChapter}
      handleAriaLabel="جابجایی فصل"
    />
  );
}
