// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { HeadlessFlatTreeItemProps } from "@coreai-ds/react-components";
import { useHeadlessFlatTree_unstable } from "@coreai-ds/react-components";
import type { DragEndEvent } from "@dnd-kit/core";
import { useSensors } from "@dnd-kit/core";
import { useSensor } from "@dnd-kit/core";
import { PointerSensor } from "@dnd-kit/core";
import { KeyboardSensor } from "@dnd-kit/core";
import { DndContext } from "@dnd-kit/core";
import { closestCenter } from "@dnd-kit/core";
import { SortableContext } from "@dnd-kit/sortable";
import { verticalListSortingStrategy } from "@dnd-kit/sortable";
import { FlatTree } from "@coreai-ds/react-components";
import type { FlatTreeItemProps } from "@coreai-ds/react-components";
import { useSortable } from "@dnd-kit/sortable";
import type { UniqueIdentifier } from "@dnd-kit/core";
import { CSS } from "@dnd-kit/utilities";
import { FlatTreeItem } from "@coreai-ds/react-components";
import { TreeItemLayout } from "@coreai-ds/react-components";

type FlatItem = HeadlessFlatTreeItemProps & {
    layout: string;
};

const flatTreeItems: FlatItem[] = [
    { value: '1', layout: 'Parent item' },
    { value: '1-1', parentValue: '1', layout: 'Sortable item 1' },
    { value: '1-2', parentValue: '1', layout: 'Sortable item 2' },
    { value: '1-3', parentValue: '1', layout: 'Sortable item 3' },
    { value: '1-4', parentValue: '1', layout: 'Sortable item 4' },
    { value: '1-5', parentValue: '1', layout: 'Sortable item 5' },
    { value: '1-6', parentValue: '1', layout: 'Sortable item 6' },
    { value: '1-7', parentValue: '1', layout: 'Sortable item 7' },
    { value: '1-8', parentValue: '1', layout: 'Sortable item 8' },
];

const sortItems = (array: FlatItem[], from: number, to: number) => {
    const newArray = array.slice();
    const startIndex = from < 0 ? array.length + from : from;
    const item = newArray.splice(startIndex, 1)[0];
    const endIndex = to < 0 ? array.length + to : to;
    newArray.splice(endIndex, 0, item);
    return newArray;
};

const SortableTreeItem = ({ children, value, ...rest }: FlatTreeItemProps) => {
    const { attributes, isDragging, listeners, setNodeRef, transform, transition } = useSortable({
        id: value as UniqueIdentifier,
    });
    const style = { transform: CSS.Transform.toString(transform), transition, zIndex: isDragging ? 1 : 0 };
    return (<FlatTreeItem ref={setNodeRef} value={value} style={style} {...attributes} {...listeners} {...rest}>
      {children}
    </FlatTreeItem>);
};

export const DragAndDrop = (): JSXElement => {
    const [items, setItems] = React.useState(flatTreeItems);
    const virtualTree = useHeadlessFlatTree_unstable(items, {
        defaultOpenItems: ['1'],
    });
    const handleDragEnd = React.useCallback((event: DragEndEvent) => {
        const { active, over } = event;
        if (active.id !== over?.id) {
            setItems(prevItems => {
                const oldIndex = prevItems.findIndex(item => item.value === active.id);
                const newIndex = prevItems.findIndex(item => item.value === over?.id);
                return sortItems(prevItems, oldIndex, newIndex);
            });
        }
    }, []);
    const sortableItems = items.filter(item => item.parentValue).map(item => item.value);
    const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor));
    return (<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
      <SortableContext items={sortableItems} strategy={verticalListSortingStrategy}>
        <FlatTree aria-label="Drag And Drop" {...virtualTree.getTreeProps()}>
          {Array.from(virtualTree.items(), item => {
            const { layout, ...itemProps } = item.getTreeItemProps();
            return item.itemType === 'leaf' ? (<SortableTreeItem key={item.value} {...itemProps}>
                <TreeItemLayout>{layout}</TreeItemLayout>
              </SortableTreeItem>) : (<FlatTreeItem {...itemProps} key={item.value}>
                <TreeItemLayout>{layout}</TreeItemLayout>
              </FlatTreeItem>);
        })}
        </FlatTree>
      </SortableContext>
    </DndContext>);
};

export default DragAndDrop;
