/**
 * Setting this attribute allows to short circuit instead of going upwards all parents. This is useful
 * if you use React's `createPortal`.
 */
const HTML_ATTRIBUTE_UNIQUE_IDENTIFIER = "interaction-player-uqid";

/**
 * If set allows you to skip this element for a next-sibling element interaction.
 * That means a `div:nth-child(3)` click would result in `div:nth-child(2)`.
 */
const HTML_ATTRIBUTE_PLAYER_SKIP = "interaction-player-skip";

const calcFullSelector = (elm: HTMLElement, until = document.body) => {
    if (elm === until || !elm?.parentElement) {
        return false;
    }

    const names = [];
    while (elm !== until && elm) {
        const uqid = elm.getAttribute(HTML_ATTRIBUTE_UNIQUE_IDENTIFIER);
        if (uqid) {
            names.unshift(`[${HTML_ATTRIBUTE_UNIQUE_IDENTIFIER}="${uqid}"]`);
            break;
        }

        let c = 1;
        let e = elm;
        for (; e.previousElementSibling; e = e.previousElementSibling as HTMLElement, c++);

        // Got this item accidentally captured through a click event? For example pointer events and bubbling
        if (elm.tagName === "HTML") {
            return false;
        }

        names.unshift(`${elm.tagName}:nth-child(${c})`);
        elm = elm.parentElement;

        if (elm === until) {
            break;
        }
    }

    return names.join(">").toLowerCase();
};

const resolveFullSelector = (element: HTMLElement, selector: string) => {
    if (selector.indexOf(HTML_ATTRIBUTE_UNIQUE_IDENTIFIER) > -1) {
        return document.querySelector(selector) as HTMLElement;
    }

    const selectorParts = selector.split(">");
    for (const selectorPart of selectorParts) {
        if (element) {
            const previousElement = element;
            element = element.querySelector(`:scope >${selectorPart}`) as HTMLElement;

            // Does it have a element which should be skipped previously?
            while (element?.hasAttribute(HTML_ATTRIBUTE_PLAYER_SKIP)) {
                element = previousElement.querySelector(
                    `:scope >${selectorPart.replace(/nth-child\((\d+)\)$/, (m, idx) => `nth-child(${+idx + 1})`)}`,
                ) as HTMLElement;
            }
        } else {
            return undefined;
        }
    }

    return element;
};

export { calcFullSelector, resolveFullSelector, HTML_ATTRIBUTE_UNIQUE_IDENTIFIER, HTML_ATTRIBUTE_PLAYER_SKIP };
