import { ref } from 'vue';
import type { Ref } from 'vue';

/**
 * Réordonnancement par glisser-déposer natif (HTML5) d’une liste
 * d’éléments identifiés par leur index. À utiliser avec `DragHandle`
 * pour la poignée ; `rowProps(index)` se pose sur la ligne.
 *
 * ```ts
 * const { rowProps, dragging, over } = useSortable((from, to) => move(from, to));
 * <tr v-bind="rowProps(index)" :class="over === index && 'bg-muted'">
 * ```
 */
export type SortableRowProps = {
    draggable: boolean;
    onDragstart: (event: DragEvent) => void;
    onDragover: (event: DragEvent) => void;
    onDragenter: (event: DragEvent) => void;
    onDragleave: () => void;
    onDrop: (event: DragEvent) => void;
    onDragend: () => void;
};

export function useSortable(onMove: (from: number, to: number) => void): {
    dragging: Ref<number | null>;
    over: Ref<number | null>;
    rowProps: (index: number) => SortableRowProps;
} {
    const dragging = ref<number | null>(null);
    const over = ref<number | null>(null);

    const reset = (): void => {
        dragging.value = null;
        over.value = null;
    };

    const rowProps = (index: number): SortableRowProps => ({
        draggable: true,
        onDragstart: (event: DragEvent) => {
            dragging.value = index;
            event.dataTransfer?.setData('text/plain', String(index));

            if (event.dataTransfer) {
                event.dataTransfer.effectAllowed = 'move';
            }
        },
        onDragover: (event: DragEvent) => {
            event.preventDefault();

            if (event.dataTransfer) {
                event.dataTransfer.dropEffect = 'move';
            }
        },
        onDragenter: (event: DragEvent) => {
            event.preventDefault();
            over.value = index;
        },
        onDragleave: () => {
            if (over.value === index) {
                over.value = null;
            }
        },
        onDrop: (event: DragEvent) => {
            event.preventDefault();

            const from = dragging.value;

            if (from !== null && from !== index) {
                onMove(from, index);
            }

            reset();
        },
        onDragend: reset,
    });

    return { dragging, over, rowProps };
}

/** Déplace un élément d’une liste (nouvelle liste, sans mutation). */
export function moveItem<T>(items: T[], from: number, to: number): T[] {
    const next = [...items];
    const [item] = next.splice(from, 1);

    next.splice(to, 0, item as T);

    return next;
}
