import { DndContext, DragOverlay, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getAnswerOptionIdsByQuestionId, getAnswerOptionsByOptionId, query, queryAll } from '../../dom-utils';
import { saveAnswer } from '../../store/answers/actions';
import { DNDTitleAndDroppable } from '../shared/DNDTitleAndDroppable';
import { AllDNDOptions } from './DNDAllOptions';
import { DNDAnswerOptionDraggable } from './DNDAnswerOptionDraggable';
import { coordinateGetter } from './multipleContainersKeyboardCoordinates';
export const DNDAnswerContainer = ({ element, renderChildNodes, renderComponentOverrides }) => {
    var _a;
    const dispatch = useDispatch();
    const [activeId, setActiveId] = useState();
    const [optionIdsByQuestionId, setOptionIdsByQuestionId] = useState({});
    const [answerOptionsById, setAnswerOptionsById] = useState({});
    const [displayNumbersById, setDisplayNumbersById] = useState({});
    const answers = useSelector((state) => state.answers);
    useEffect(() => {
        const dndAnswers = queryAll(element, 'dnd-answer').filter(e => !!query(e, 'dnd-answer-title'));
        const answerOptionIdsByQuestionId = getAnswerOptionIdsByQuestionId(element, answers.answersById);
        const answerOptionsByOptionId = getAnswerOptionsByOptionId(element);
        const displayNumbersById = dndAnswers.reduce((acc, el) => {
            const questionId = el.getAttribute('question-id');
            const displayNumber = el.getAttribute('display-number');
            return { ...acc, [questionId]: displayNumber };
        }, {});
        setOptionIdsByQuestionId(answerOptionIdsByQuestionId);
        setAnswerOptionsById(answerOptionsByOptionId);
        setDisplayNumbersById(displayNumbersById);
    }, [element]);
    const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
        coordinateGetter
    }));
    function findContainer(id) {
        if (id in optionIdsByQuestionId) {
            return id;
        }
        return Object.keys(optionIdsByQuestionId).find(key => optionIdsByQuestionId[key].includes(id));
    }
    function getContainers(event) {
        const { active, over } = event;
        const optionId = active.id;
        const questionIdFrom = findContainer(optionId);
        const questionIdTo = over === null || over === void 0 ? void 0 : over.id;
        return { optionId, questionIdFrom, questionIdTo };
    }
    function handleDragStart(event) {
        setActiveId(event.active.id);
    }
    function handleDragEnd(event) {
        const { optionId, questionIdFrom, questionIdTo } = getContainers(event);
        if (!questionIdFrom || !questionIdTo || questionIdFrom === questionIdTo) {
            return;
        }
        setOptionIdsByQuestionId(optionIdsByQuestionId => moveValue(optionIdsByQuestionId, questionIdFrom, questionIdTo, optionId));
        if (questionIdFrom !== 'root') {
            saveAnswerToStore(questionIdFrom, '');
        }
        if (questionIdTo !== 'root') {
            saveAnswerToStore(questionIdTo, optionId);
        }
        setActiveId(null);
    }
    function saveAnswerToStore(questionId, optionId) {
        const questionIdNumber = Number(questionId);
        const value = (optionId === null || optionId === void 0 ? void 0 : optionId.toString()) || '';
        const displayNumber = displayNumbersById[questionId];
        dispatch(saveAnswer({ type: 'choice', questionId: questionIdNumber, value, displayNumber }));
    }
    const dndAnswersWithQuestion = queryAll(element, 'dnd-answer').filter(e => !!query(e, 'dnd-answer-title'));
    const allAnswerOptionElements = (_a = optionIdsByQuestionId.root) === null || _a === void 0 ? void 0 : _a.map(id => answerOptionsById[id] || null).filter(Boolean);
    // We can not render the prop 'element' (XML) here, because we will change the DOM structure when items are dragged around¯, but the XML can not be changed
    return (React.createElement("div", { className: "e-dnd-answer-container" },
        React.createElement(DndContext, { sensors: sensors, onDragStart: handleDragStart, onDragEnd: handleDragEnd },
            dndAnswersWithQuestion.map(element => {
                var _a;
                const questionId = element.getAttribute('question-id');
                const dndAnswerOptions = (_a = (optionIdsByQuestionId[questionId] || [])) === null || _a === void 0 ? void 0 : _a.map(id => (answerOptionsById === null || answerOptionsById === void 0 ? void 0 : answerOptionsById[id]) || null).filter(Boolean);
                const itemIds = optionIdsByQuestionId[questionId] || [];
                return (React.createElement(DNDTitleAndDroppable, { key: questionId, element: element, renderChildNodes: renderChildNodes, renderComponentOverrides: renderComponentOverrides, itemIds: itemIds, answerOptionElements: dndAnswerOptions, page: "exam" }));
            }),
            React.createElement(AllDNDOptions, { items: optionIdsByQuestionId.root || [], renderChildNodes: renderChildNodes, renderComponentOverrides: renderComponentOverrides, answerOptionElements: allAnswerOptionElements }),
            React.createElement(DragOverlay, { className: "e-dnd-answer-drag-overlay", dropAnimation: {
                    duration: 250,
                    easing: 'ease-in-out'
                } }, activeId ? (React.createElement(DNDAnswerOptionDraggable, { element: answerOptionsById[activeId], renderChildNodes: renderChildNodes, renderComponentOverrides: renderComponentOverrides })) : null))));
};
function moveValue(state, from, to, value) {
    const newState = { ...state };
    // Remove the value from its current container
    newState[from] = newState[from].filter(item => item !== value);
    if (to === 'root') {
        // add the value to root
        newState.root = [value, ...newState.root];
    }
    else {
        // If the target container is not empty, move the existing value back to root
        if (newState[to].length > 0) {
            const existingValue = newState[to][0];
            newState.root = [...newState.root, existingValue];
        }
        // Move the new value to the target container
        newState[to] = [value];
    }
    return newState;
}
//# sourceMappingURL=DNDAnswerContainer.js.map