import * as _ from 'lodash-es';
import { ExamNamespaceURI } from './createRenderChildNodes';
import { useContext, useEffect, useState } from 'react';
import { TOCContext } from './components/context/TOCContext';
export const NBSP = '\u00A0';
export function parentElements(element, selector) {
    const predicate = selector != null ? mkPredicate(selector) : undefined;
    const result = [];
    while (element.parentElement != null) {
        element = element.parentElement;
        if (predicate == null || predicate(element)) {
            result.push(element);
        }
    }
    return result;
}
function mkPredicate(selector) {
    return typeof selector === 'function'
        ? (element) => element.namespaceURI === ExamNamespaceURI && selector(element)
        : Array.isArray(selector)
            ? (element) => element.namespaceURI === ExamNamespaceURI && selector.includes(element.localName)
            : (element) => element.namespaceURI === ExamNamespaceURI && element.localName === selector;
}
export function query(root, selector) {
    const predicate = mkPredicate(selector);
    function go(element) {
        for (let i = 0, length = element.children.length; i < length; i++) {
            const childElement = element.children[i];
            if (predicate(childElement)) {
                return childElement;
            }
            const maybeElement = go(childElement);
            if (maybeElement != null) {
                return maybeElement;
            }
        }
    }
    return go(root);
}
export function queryAll(root, selector, recurse = true) {
    const predicate = mkPredicate(selector);
    const results = [];
    function go(element) {
        for (let i = 0, length = element.children.length; i < length; i++) {
            const childElement = element.children[i];
            if (predicate(childElement)) {
                results.push(childElement);
                if (recurse) {
                    go(childElement);
                }
            }
            else {
                go(childElement);
            }
        }
    }
    go(root);
    return results;
}
export function queryAncestors(element, selector) {
    const predicate = mkPredicate(selector);
    while (element.parentElement != null) {
        element = element.parentElement;
        if (predicate(element)) {
            return element;
        }
    }
}
export function findChildElement(element, selector) {
    const predicate = mkPredicate(selector);
    for (let i = 0, length = element.children.length; i < length; i++) {
        const childElement = element.children[i];
        if (predicate(childElement)) {
            return childElement;
        }
    }
}
export function getAttribute(element, attributeName) {
    var _a;
    return (_a = element.getAttribute(attributeName)) !== null && _a !== void 0 ? _a : undefined;
}
export function getNumericAttribute(element, attributeName) {
    const maybeValue = element.getAttribute(attributeName);
    return maybeValue != null ? Number(maybeValue) : undefined;
}
export function getBooleanAttribute(element, attributeName) {
    return getAttribute(element, attributeName) === 'true';
}
export function mapChildNodes(element, fn) {
    const length = element.childNodes.length;
    const result = new Array(length);
    for (let i = 0; i < length; i++) {
        result[i] = fn(element.childNodes[i], i);
    }
    return result;
}
export function mapChildElements(element, fn) {
    const result = [];
    for (let i = 0, length = element.children.length; i < length; i++) {
        const childElement = element.children[i];
        result.push(fn(childElement, i));
    }
    return result;
}
export function findChildrenAnswers(element) {
    return queryAll(element, ['choice-answer', 'dropdown-answer', 'text-answer', 'scored-text-answer', 'dnd-answer', 'audio-answer'], true);
}
export function hasSiblingQuestions(answer) {
    const parentQuestion = queryAncestors(answer, 'question');
    const siblingQuestions = parentQuestion === null || parentQuestion === void 0 ? void 0 : parentQuestion.querySelectorAll('[question-id]');
    return siblingQuestions && (siblingQuestions === null || siblingQuestions === void 0 ? void 0 : siblingQuestions.length) > 1;
}
export function createElement(tagName, properties, ...children) {
    const element = document.createElement(tagName);
    setProperties(element, properties);
    children.forEach(c => element.appendChild(typeof c === 'string' ? new Text(c) : c));
    return element;
}
export function setProperties(element, properties) {
    _.forEach(properties, (v, k) => {
        if (k === 'css') {
            element.style.cssText = v;
        }
        else if (k.startsWith('data-')) {
            element.setAttribute(k, v);
        }
        else {
            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
            ;
            element[k] = v;
        }
    });
}
export function useIsElementInViewport(elementType, displayNumber) {
    const { visibleTOCElements } = useContext(TOCContext);
    const [isVisible, setIsVisible] = useState(false);
    const id = `${elementType}-${displayNumber}`;
    useEffect(() => {
        if ((visibleTOCElements === null || visibleTOCElements === void 0 ? void 0 : visibleTOCElements.includes(id)) && !isVisible) {
            setIsVisible(true);
        }
        else if (!(visibleTOCElements === null || visibleTOCElements === void 0 ? void 0 : visibleTOCElements.includes(id)) && isVisible) {
            setIsVisible(false);
        }
    }, [visibleTOCElements]);
    return isVisible;
}
export function getElementPath(element) {
    var _a, _b, _c;
    const index = !element.tagName && Array.from(((_a = element.parentNode) === null || _a === void 0 ? void 0 : _a.childNodes) || []).indexOf(element);
    const elementIndex = Array.from(((_b = element.parentElement) === null || _b === void 0 ? void 0 : _b.children) || []).indexOf(element);
    let path = `${element.nodeName}:${elementIndex > 0 ? elementIndex : index}`;
    let currentElement = element;
    while (currentElement.parentElement) {
        currentElement = currentElement.parentElement;
        const displayNumber = currentElement.getAttribute('display-number');
        const isNumber = Number(displayNumber);
        const index = isNumber
            ? displayNumber
            : Array.from(((_c = currentElement.parentElement) === null || _c === void 0 ? void 0 : _c.children) || [currentElement]).indexOf(currentElement);
        const elementId = currentElement.getAttribute('id');
        path = `${elementId || currentElement.nodeName}:${index} > ${path}`;
    }
    return path;
}
// For DND answers
export const getAnswerOptionIdsByQuestionId = (element, answersById) => {
    const dndAnswers = queryAll(element, 'dnd-answer');
    const dndAnswerOptions = queryAll(element, 'dnd-answer-option');
    const answerOptionIdsByQuestionId = dndAnswers.reduce((acc, group) => {
        var _a;
        const questionId = group.getAttribute('question-id');
        const answer = (_a = answersById[Number(questionId)]) === null || _a === void 0 ? void 0 : _a.value;
        return {
            ...acc,
            [questionId]: answer ? [Number(answer)] : [],
            root: acc.root.filter(e => e !== Number(answer))
        };
    }, { root: dndAnswerOptions.map(e => Number(e.getAttribute('option-id'))) });
    return answerOptionIdsByQuestionId;
};
export const getAnswerOptionsByOptionId = (element) => {
    const dndAnswerOptions = queryAll(element, 'dnd-answer-option');
    const answerOptionsByOptionId = dndAnswerOptions.reduce((acc, el) => {
        const optionId = el.getAttribute('option-id');
        return { ...acc, [optionId]: el };
    }, {});
    return answerOptionsByOptionId;
};
export const getCorrectAnswerOptionIdsByQuestionId = (element) => {
    const correctAnswerOptionsByQuestionId = queryAll(element, 'dnd-answer-option').reduce((acc, el) => {
        const questionId = el.getAttribute('for-question-id');
        const optionId = el.getAttribute('option-id');
        if (!questionId) {
            return acc;
        }
        const current = acc[questionId] || [];
        return { ...acc, [questionId]: current.concat(optionId) };
    }, {});
    return correctAnswerOptionsByQuestionId;
};
export function wrapAllImages(answerElement) {
    answerElement.querySelectorAll('img').forEach(getWrapper);
}
export function getWrapper(image) {
    const parent = image.parentElement;
    if (parent instanceof HTMLSpanElement) {
        return parent;
    }
    const wrapper = createElement('span', { className: 'e-image-wrapper' });
    parent.insertBefore(wrapper, image);
    wrapper.appendChild(image);
    return wrapper;
}
//# sourceMappingURL=dom-utils.js.map