
function generateSelector(el) {
    if (!(el instanceof Element)) return '';

    const path = [];
    while (el.nodeType === Node.ELEMENT_NODE) {
        let selector = el.nodeName.toLowerCase();
        if (el.id) {
            selector = '#' + el.id.trim();
            path.unshift(selector);
            break;
        } else {
            let classes = Array.from(el.classList).filter(cls => cls.trim() !== '');
            if (classes.length > 0) {
                 selector += '.' + classes.join('.');
            }

            let sibling = el;
            let nth = 1;
            let hasSimilarSiblings = false;
            while (sibling = sibling.previousElementSibling) {
                if (sibling.nodeName.toLowerCase() === selector.split('.')[0]) {
                     nth++;
                     if (!hasSimilarSiblings && generateSelectorPart(sibling) === generateSelectorPart(el)) {
                          hasSimilarSiblings = true;
                     }
                }
            }

            if (nth > 1 && (!classes.length || hasSimilarSiblings)) {
                selector += `:nth-of-type(${nth})`;
            }
        }
        path.unshift(selector);
        el = el.parentNode;
        if (el && el.nodeName.toLowerCase() === 'body') {
             path.unshift('body');
             break;
        }
    }
    return path.join(' > ');
}

function generateSelectorPart(el) {
     let selector = el.nodeName.toLowerCase();
     let classes = Array.from(el.classList).filter(cls => cls.trim() !== '');
     if (classes.length > 0) {
          selector += '.' + classes.join('.');
     }
     return selector;
}

window.$x = function (xpath) {
    function convertToElements(result) {
        var a = [];
        for (var i = 0; i < result.snapshotLength; i++) {
            a.push(result.snapshotItem(i));
        }
        return a;
    }

    result = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    return convertToElements(result);
}

window.getElementsDump = function () {
    var visibleElements = angular.element('*:visible');
    var elements = [];
    visibleElements.each(function (index, element) {
        const info = {};
        info.tagName = element.tagName;
        info.selector = generateSelector(element);

        const rect = element.getBoundingClientRect();

        info.rect = {
            x: Math.round(rect.x),
            y: Math.round(rect.y),
            width: Math.round(rect.width),
            height: Math.round(rect.height)
        };

        info.attributes = {};
        if (element.hasAttributes()) {
            for (const attr of element.attributes) {
                let attrValue = attr.value;
                if (attrValue && attrValue.length > 256) {
                    attrValue = attrValue.substring(0, 256) + '...';
                }
                info.attributes[attr.name] = attrValue;
            }
        }

        try {
            info.classList = Array.from(element.classList);

            let textContent = element.textContent?.trim();
            if (textContent && textContent.length > 100) {
                textContent = textContent.substring(0, 100) + '...';
            }
            info.textContent = textContent || '';

            const computedStyle = window.getComputedStyle(element);
            info.computedStyles = {
                display: computedStyle.getPropertyValue('display'),
                visibility: computedStyle.getPropertyValue('visibility'),
                opacity: computedStyle.getPropertyValue('opacity'),
                zIndex: computedStyle.getPropertyValue('z-index'),
                color: computedStyle.getPropertyValue('color'),
                backgroundColor: computedStyle.getPropertyValue('background-color'),
                fontSize: computedStyle.getPropertyValue('font-size'),
            };
        } catch (e) {
            console.warn("Could not get extended info for element:", element, e);
            info.classList = [];
            info.textContent = '[Error]';
            info.computedStyles = {};
        }
        elements.push(info);
    });
    return JSON.stringify(elements);
}

function triggerInput(inputEl, value) {

    const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;

    nativeInputValueSetter.call(inputEl, value);


    const event = new Event('change', {bubbles: true});

    inputEl.dispatchEvent(event);

}

window.triggerInput = triggerInput