export const VerticalMovementDirection = {
    top: -1,
    bottom: 1,
};
export const generateUniqueGroupId = () => {
    if (process.env.NODE_ENV === 'test') {
        return 'test_id';
    }
    return Symbol('nestable-list-base-id');
};
export const getDepth = (item, childrenProperty) => {
    // returns depth of item and children
    let depth = 0;
    if (item[childrenProperty]) {
        item[childrenProperty].forEach(d => {
            const tmpDepth = getDepth(d, childrenProperty);
            if (tmpDepth > depth) {
                depth = tmpDepth;
            }
        });
    }
    return depth + 1;
};
export const getValuesByKey = (data, key, childrenProp) => {
    const values = [data[key]];
    if (data[childrenProp]) {
        data[childrenProp].forEach(item => {
            values.push(...getValuesByKey(item, key, childrenProp));
        });
    }
    return values;
};
const arrayRemove = (items, index) => {
    return [...items.slice(0, index), ...items.slice(index + 1)];
};
const arrayAdd = (items, index, item) => {
    return [...items.slice(0, index), item, ...items.slice(index)];
};
export function removeFromTree(items, position, childrenProperty) {
    if (position.length === 0) {
        return items;
    }
    const [currentIndex, ...restPosition] = position;
    if (restPosition.length === 0) {
        return arrayRemove(items, currentIndex);
    }
    // Recursively process nested items
    return items.map((item, index) => {
        if (index === currentIndex) {
            return {
                ...item,
                [childrenProperty]: removeFromTree(item[childrenProperty] ?? [], restPosition, childrenProperty),
            };
        }
        return item;
    });
}
export function addToTree(items, item, position, childrenProperty) {
    if (position.length === 0) {
        return items;
    }
    const [currentIndex, ...restPosition] = position;
    if (restPosition.length === 0) {
        return arrayAdd(items, currentIndex, item);
    }
    // Recursively process nested items
    return items.map((currentItem, index) => {
        if (index === currentIndex) {
            return {
                ...currentItem,
                [childrenProperty]: addToTree(currentItem[childrenProperty] ?? [], item, restPosition, childrenProperty),
            };
        }
        return currentItem;
    });
}
export function swapItems(items, firstItem, secondItem, childProp = 'children') {
    return recursiveMap(items, item => {
        if (item.id === firstItem.id) {
            return secondItem;
        }
        if (item.id === secondItem.id) {
            return firstItem;
        }
        return item;
    }, childProp);
}
export function getSiblingsByNodePosition(items, position = [], childProp = 'children') {
    return position.reduce((siblings, pos, i) => {
        if (siblings && siblings[pos]) {
            if (position.length - 1 === i) {
                return siblings;
            }
            return siblings[pos][childProp];
        }
        return null;
    }, items);
}
export function getNodeAtPosition(items, position = [], childProp = 'children') {
    return position.reduce((siblings, pos, i) => {
        if (siblings[pos]) {
            if (position.length - 1 === i) {
                return siblings[pos];
            }
            return siblings[pos][childProp];
        }
        return null;
    }, items);
}
export function getNodePosition(items, item, childProp = 'children', position = []) {
    if (!items) {
        return;
    }
    for (let i = 0; i < items.length; i++) {
        const currentPosition = [...position, i];
        if (item.id === items[i].id) {
            return currentPosition;
        }
        const nodePosition = getNodePosition(items[i][childProp], item, childProp, currentPosition);
        if (nodePosition) {
            return nodePosition;
        }
    }
}
export function recursiveMap(items, predicateFn, childProp = 'children') {
    return items.map(currentItem => {
        const item = predicateFn(currentItem);
        if (item !== currentItem) {
            return item;
        }
        if (currentItem[childProp]) {
            return {
                ...currentItem,
                children: recursiveMap(currentItem[childProp], predicateFn),
            };
        }
        return currentItem;
    });
}
export function isLastItem(siblings, item) {
    return siblings && siblings[siblings.length - 1] === item;
}
export function isFistItem(siblings, item) {
    return siblings && siblings[0] === item;
}
export function isRootItem(depth) {
    return depth === 1;
}
export function hoverAboveItself(prevPosition, nextPosition) {
    return prevPosition.every((position, index) => {
        return nextPosition[index] === position;
    });
}
export function isItemHasChildren(item, childrenProperty) {
    return Boolean(item[childrenProperty] && item[childrenProperty].length);
}
export function getDropParent(items, nextPosition, childrenProperty) {
    return nextPosition
        .slice(1, nextPosition.length - 1)
        .reduce((item, childIndex) => {
        if (!item) {
            return null;
        }
        return item[childrenProperty][childIndex];
    }, items[nextPosition[0]]);
}
export function moveItem(items, item, currentPosition, newPosition, childrenProp = 'children') {
    items = removeFromTree(items, currentPosition, childrenProp);
    return addToTree(items, item, newPosition, childrenProp);
}
export function moveItemToTheChildOfPrevSibling(items, item, childrenProp = 'children') {
    const currentPosition = getNodePosition(items, item, childrenProp);
    // if there is not prev sibling we cannot move
    if (currentPosition[currentPosition.length - 1] === 0) {
        return items;
    }
    const newPosition = currentPosition.reduce((acc, pos, index, arr) => {
        if (index === arr.length - 1) {
            acc.push(pos - 1);
            acc.push(0);
        }
        else {
            acc.push(pos);
        }
        return acc;
    }, []);
    return moveItem(items, item, currentPosition, newPosition);
}
function getVerticalMovedPosition(items, position, step, childProp = 'children') {
    const suitableNextParent = [...position]
        .reverse()
        .reduce((acc, pos, index) => {
        if (acc) {
            return acc;
        }
        const prefix = position.slice(0, position.length - 1 - index);
        const siblings = getSiblingsByNodePosition(items, position.slice(0, position.length - index), childProp);
        for (let i = pos + step; i >= 0 && i < siblings.length; i += step) {
            const candidate = [...prefix, i];
            const candidateSiblings = getSiblingsByNodePosition(items, candidate, childProp);
            if (!candidateSiblings) {
                return null;
            }
            const totalDepth = getDepth(getNodeAtPosition(items, candidate, childProp), childProp) +
                position.length -
                index;
            if (totalDepth >= position.length) {
                return candidate;
            }
        }
        return acc;
    }, null);
    if (!suitableNextParent) {
        return null;
    }
    if (position.length === suitableNextParent.length) {
        return suitableNextParent;
    }
    return position.reduce((acc, _, index) => {
        const lastItem = index === position.length - 1;
        if (suitableNextParent[index] !== undefined) {
            acc.push(suitableNextParent[index]);
        }
        else {
            const siblings = getSiblingsByNodePosition(items, [...acc, 0], childProp);
            if (!siblings) {
                acc.push(0);
                return acc;
            }
            const maxIndex = lastItem ? siblings.length : siblings.length - 1;
            let candidateIndex = step < 0 ? maxIndex : 0;
            while (candidateIndex >= 0 && candidateIndex <= maxIndex) {
                const candidate = [...acc, candidateIndex];
                if (lastItem) {
                    return candidate;
                }
                const candidateDepth = getDepth(getNodeAtPosition(items, candidate, childProp), childProp) +
                    index;
                if (candidateDepth < position.length - 1) {
                    candidateIndex += step;
                    continue;
                }
                return candidate;
            }
        }
        return acc;
    }, []);
}
function getParentPosition(position) {
    return position.slice(0, position.length - 1);
}
export function moveItemVertically({ items, item, step = VerticalMovementDirection.bottom, childProp = 'children', preventChangeParent = false, enforcePinnedOrder = false, }) {
    const currentPosition = getNodePosition(items, item, childProp);
    const newPosition = getVerticalMovedPosition(items, currentPosition, step, childProp);
    if (!newPosition) {
        return items;
    }
    if (preventChangeParent) {
        const prevParentPath = currentPosition.slice(0, -1);
        const nextParentPath = newPosition.slice(0, -1);
        const prevParent = getDropParent(items, prevParentPath, childProp);
        const nextParent = getDropParent(items, nextParentPath, childProp);
        if (prevParent?.id !== nextParent?.id) {
            return items;
        }
    }
    if (enforcePinnedOrder) {
        const siblings = getSiblingsByNodePosition(items, newPosition, childProp);
        const targetItem = siblings?.[newPosition[newPosition.length - 1]];
        const shouldProhibitPinMoveDown = !!item.isPinned && !targetItem.isPinned;
        const shouldProhibitNonPinMoveUp = !item.isPinned && !!targetItem.isPinned;
        if (shouldProhibitPinMoveDown || shouldProhibitNonPinMoveUp) {
            return items;
        }
    }
    return moveItem(items, item, currentPosition, newPosition, childProp);
}
export function moveItemOutsideOfTheParent(items, item, childProp = 'children') {
    const currentPosition = getNodePosition(items, item, childProp);
    // if currentPosition is root of the tree we cannot move item to the left
    if (currentPosition.length < 2) {
        return items;
    }
    const newPosition = getParentPosition(currentPosition);
    newPosition[newPosition.length - 1] = newPosition[newPosition.length - 1] + 1;
    return moveItem(items, item, currentPosition, newPosition);
}
export function setCollapse(items, itemId, isCollapsed) {
    return recursiveMap(items, item => {
        if (itemId === item.id) {
            return {
                ...item,
                isCollapsed,
            };
        }
        return item;
    });
}
//# sourceMappingURL=utils.js.map