"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Element = void 0;
const exception_js_1 = require("../exception.js");
const util = __importStar(require("./util/index.js"));
class Element {
    constructor(remote, value, info) {
        this.remote = remote;
        this.value = value;
        this.info = info;
    }
    get objectId() {
        return this.remote.objectId;
    }
    get description() {
        return this.remote.description;
    }
    get page() {
        return this.remote.page;
    }
    get executionContext() {
        return this.remote.executionContext;
    }
    clone(newValue = this.value) {
        const val = util.deepClone(newValue);
        return new Element(this.remote, val, this.info);
    }
    async getInfo(force = false) {
        if (force || !this.info) {
            this.info = await this.remote.getInfo();
        }
        return this.info;
    }
    async evaluateJson(pageFn, ...args) {
        return await this.executionContext.evaluateJson(pageFn, this.remote, ...args);
    }
    async queryAll(selector, optional = false) {
        const obj = await this.executionContext.evaluate((root, sel, toolkitBinding) => {
            const nodeList = root.querySelectorAll(sel);
            const infos = [];
            for (const newEl of nodeList) {
                infos.push(window[toolkitBinding].getElementInfo(newEl));
            }
            return {
                nodeList,
                infos,
            };
        }, this.remote, selector, this.page.toolkitBinding);
        const newEls = await this.extractElementsWithInfo(obj);
        if (newEls.length === 0 && !optional) {
            throw new exception_js_1.Exception({
                name: 'SelectorNotFound',
                message: 'No elements found by selector. Use optional: true to return 0 elements.',
                retry: true,
                details: { selector, optional },
            });
        }
        return newEls;
    }
    async queryOne(selector, optional = false) {
        const newEls = await this.queryAll(selector, optional);
        if (newEls.length > 1) {
            throw new exception_js_1.Exception({
                name: 'SelectorAmbiguous',
                message: 'Multiple elements found by selector. Use queryAll to return multiple elements.',
                retry: true,
                details: { selector, optional },
            });
        }
        return newEls[0];
    }
    async queryXPathAll(expression, optional = false) {
        const remotes = await this.remote.queryXPathAll(expression);
        const newEls = remotes.map(r => new Element(r, this.value));
        if (newEls.length === 0 && !optional) {
            throw new exception_js_1.Exception({
                name: 'XpathNotFound',
                message: 'No elements found by Xpath expression. Use optional: true to return 0 elements.',
                retry: true,
                details: { expression, optional },
            });
        }
        return newEls;
    }
    async queryXPathOne(expression, optional = false) {
        const newEls = await this.queryXPathAll(expression, optional);
        if (newEls.length > 1) {
            throw new exception_js_1.Exception({
                name: 'XpathAmbiguous',
                message: 'Multiple elements found by Xpath expression. Use queryXpathAll to return multiple elements.',
                retry: true,
                details: { expression, optional },
            });
        }
        return newEls[0];
    }
    async parent(optional) {
        const newRemote = await this.remote.parent();
        util.assertPlayback(newRemote || optional, 'Parent element not found');
        return newRemote ? new Element(newRemote, this.value) : null;
    }
    async children(optional = false) {
        const obj = await this.executionContext.evaluate((root, toolkitBinding) => {
            const nodeList = root.children;
            const infos = [];
            for (const newEl of nodeList) {
                infos.push(window[toolkitBinding].getElementInfo(newEl));
            }
            return {
                nodeList,
                infos,
            };
        }, this.remote, this.page.toolkitBinding);
        const newEls = await this.extractElementsWithInfo(obj);
        util.assertPlayback(newEls.length > 0 || optional, 'No child elements found. Use optional: true to return 0 elements.');
        return newEls;
    }
    async previousSibling(optional) {
        const newRemote = await this.remote.previousSibling();
        util.assertPlayback(newRemote || optional, 'Previous sibling element not found');
        return newRemote ? new Element(newRemote, this.value) : null;
    }
    async nextSibling(optional) {
        const newRemote = await this.remote.nextSibling();
        util.assertPlayback(newRemote || optional, 'Next sibling element not found');
        return newRemote ? new Element(newRemote, this.value) : null;
    }
    async closest(selector, optional = false) {
        const newRemote = await this.remote.closest(selector);
        util.assertPlayback(newRemote || optional, 'No ancestor found by selector. Use optional: true to return null');
        return newRemote ? new Element(newRemote, this.value) : null;
    }
    async contentDocument() {
        const newRemote = await this.remote.contentDocument();
        return new Element(newRemote, this.value);
    }
    async shadowRoot() {
        const newRemote = await this.remote.shadowRoot();
        return new Element(newRemote, this.value);
    }
    async assertElement(message) {
        const nodeType = await this.remote.evaluateJson(el => el.nodeType);
        if (nodeType !== 1) {
            throw new exception_js_1.Exception({
                name: 'InvalidDomElement',
                message,
                retry: true,
            });
        }
    }
    async extractElementsWithInfo(obj) {
        const nodeList = await this.executionContext.evaluate(obj => obj.nodeList, obj);
        const infos = await this.executionContext.evaluateJson(obj => obj.infos, obj);
        const remoteEls = await this.executionContext.nodeListToElements(nodeList);
        const result = [];
        for (const [i, remoteEl] of remoteEls.entries()) {
            const info = infos[i];
            result.push(new Element(remoteEl, this.value, info));
        }
        return result;
    }
    async tooltip(label, color = 'hsla(144, 48%, 48%, .4)') {
        try {
            const target = this.remote.isOption() ? await this.remote.closest('select') : this.remote;
            const key = target.objectId.replace(/[^a-z0-9]/gi, '');
            await this.executionContext.evaluate((el, key, ttl, label, color, toolkitBinding) => {
                window[toolkitBinding].showRect(el, {
                    key,
                    ttl,
                    label,
                    color,
                });
            }, target, key, 1000, label, color, this.page.toolkitBinding);
        }
        catch (e) {
        }
    }
}
exports.Element = Element;
//# sourceMappingURL=element.js.map