import {
    HTML_ATTRIBUTE_BLOCKER_CONNECTED,
    HTML_ATTRIBUTE_BLOCKER_ID,
    HTML_ATTRIBUTE_THUMBNAIL,
} from "../dom/htmlAttributes.js";
import { getPreviousVisibleElement } from "../utils/previousVisibleElement.js";

function isHtmlNodeContentBlocker(node: HTMLElement) {
    return node.hasAttribute(HTML_ATTRIBUTE_BLOCKER_CONNECTED);
}

function mapIgnoreInvisibleAndUsePreviousVisible(element: HTMLElement) {
    return element.offsetParent ? element : getPreviousVisibleElement(element, isHtmlNodeContentBlocker);
}

/**
 * Find a duplicate before a given node to avoid duplicate content blockers for the same content.
 */
function findPreviousVisibleDuplicate(
    createBefore: HTMLElement,
    node: HTMLElement,
    blockerId: number,
    /**
     * If `true`, exceptions will be disabled. For example, if the blocked node has a visual thumbnail,
     * check if the blocked content of the possible duplicate has not the same visual thumbnail.
     */
    disableExceptions?: boolean,
) {
    const { previousElementSibling } = createBefore;
    const visualThumbnail = node.getAttribute(HTML_ATTRIBUTE_THUMBNAIL);
    const firstParentPreviousElementSibling = createBefore.parentElement?.previousElementSibling;
    const secondParentPreviousElementSibling = createBefore.parentElement?.parentElement?.previousElementSibling;
    const possibleDuplicates = (
        [
            getPreviousVisibleElement(createBefore, isHtmlNodeContentBlocker),
            previousElementSibling,
            previousElementSibling?.lastElementChild,
            // 1st parent up
            firstParentPreviousElementSibling,
            firstParentPreviousElementSibling?.lastElementChild,
            // 2nd parent up
            secondParentPreviousElementSibling,
            secondParentPreviousElementSibling?.lastElementChild,
            secondParentPreviousElementSibling?.lastElementChild?.lastElementChild,
        ] as HTMLElement[]
    )
        .filter(Boolean)
        // Get previous visible element if the last child element is not visible
        .map(mapIgnoreInvisibleAndUsePreviousVisible)
        .filter(Boolean);
    for (const possibleDuplicate of possibleDuplicates) {
        if (
            +possibleDuplicate.getAttribute(HTML_ATTRIBUTE_BLOCKER_ID) === blockerId &&
            possibleDuplicate.hasAttribute(HTML_ATTRIBUTE_BLOCKER_CONNECTED)
        ) {
            const connected = +possibleDuplicate.getAttribute(HTML_ATTRIBUTE_BLOCKER_CONNECTED);

            if (!disableExceptions) {
                // If the blocked node has a visual thumbnail, check if the blocked content of
                // the possible duplicate has not the same visual thumbnail. Otherwise, use it
                // as duplicate.
                const blockedContentOfPossibleDuplicate = document.querySelector(
                    `[${HTML_ATTRIBUTE_BLOCKER_CONNECTED}="${connected}"]:not(.rcb-content-blocker)`,
                );
                if (
                    visualThumbnail &&
                    blockedContentOfPossibleDuplicate?.hasAttribute(HTML_ATTRIBUTE_THUMBNAIL) &&
                    blockedContentOfPossibleDuplicate.getAttribute(HTML_ATTRIBUTE_THUMBNAIL) !== visualThumbnail
                ) {
                    return false;
                }
            }

            return possibleDuplicate as HTMLElement;
        }
    }

    return false;
}

export { findPreviousVisibleDuplicate };
