import { ReactElement, useRef } from "react"
import Draggable from "react-draggable"

export interface RackProps<E extends { key: string | number }> {
    id: string
    objects: E[]
    onChange?: (objects: E[]) => void
    canDetach: (ref: HTMLDivElement) => boolean
    onElementDetached: (ref: HTMLDivElement, el: E) => void
    render: (e: E) => ReactElement
}

interface RackItemProps<E extends { key: string | number }> {
    item: E
    onTryDetach: (ref: HTMLDivElement, el: E) => void
    render: (e: E) => ReactElement
}

/**
 * A container of draggable objects
 * */
export function Rack<E extends { key: string | number }>({
    id,
    objects,
    onChange,
    canDetach,
    onElementDetached,
    render,
}: RackProps<E>) {
    return (
        <div
            id={id}
            style={{
                display: "flex",
            }}>
            {objects.map((element) => (
                <RackItem
                    key={element.key}
                    item={element}
                    render={render}
                    onTryDetach={(ref, element) => {
                        if (!canDetach(ref)) return

                        const index = objects.findIndex(
                            (o) => o.key === element.key,
                        )
                        if (onChange) onChange(objects.toSpliced(index, 1))

                        onElementDetached(ref, element)
                    }}
                />
            ))}
        </div>
    )
}

function RackItem<E extends { key: string | number }>({
    item,
    onTryDetach,
    render,
}: RackItemProps<E>) {
    const divRef = useRef<HTMLDivElement>(null)

    return (
        <Draggable
            position={{ x: 0, y: 0 }}
            nodeRef={divRef}
            onStop={() => onTryDetach(divRef.current!, item)}>
            <div ref={divRef}>{render(item)}</div>
        </Draggable>
    )
}
