"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Session = void 0;
exports.attachToSession = attachToSession;
const protocolCommands_1 = require("./protocolCommands");
const element_1 = require("./element");
const transport_1 = require("./transport");
const COMMANDS_TO_SKIP = new Set([
    'newSession',
    'findElement',
    'findElements',
    'findElementFromElement',
    'findElementsFromElement',
    'executeScript',
    'executeAsyncScript',
]);
const COMMAND_ALIASES = {
    deleteSession: 'quit',
};
class Session {
    connection;
    sessionCapabilities;
    constructor(connection, capabilities) {
        this.connection = connection;
        this.sessionCapabilities = capabilities;
    }
    async cmd(commandName, ...args) {
        return (0, transport_1.sendProtocolCommand)(this.connection, commandName, args);
    }
    get connectedUrl() {
        return this.connection.baseUrl;
    }
    get sessionId() {
        return this.connection.sessionId;
    }
    get capabilities() {
        return this.sessionCapabilities;
    }
    async findElement(using, value) {
        const response = await this.cmd('findElement', using, value);
        return (0, element_1.elementFromResponse)(response, this);
    }
    async findElements(using, value) {
        const responses = (await this.cmd('findElements', using, value));
        return responses.map((response) => (0, element_1.elementFromResponse)(response, this));
    }
    async waitForElement(ms, using, value) {
        const end = Date.now() + ms;
        let element;
        while (!element && Date.now() < end) {
            try {
                element = await this.findElement(using, value);
            }
            catch {
            }
        }
        if (element) {
            return element;
        }
        throw new Error(`Could not find element using strategy ${using} and value '${value}' after ${ms}ms`);
    }
    async waitForElements(ms, using, value) {
        const end = Date.now() + ms;
        let elements = [];
        while (elements.length === 0 && Date.now() < end) {
            elements = await this.findElements(using, value);
        }
        if (elements.length) {
            return elements;
        }
        throw new Error(`Could not find any elements using strategy ${using} and value '${value}' after ${ms}ms`);
    }
    async executeBase(command, script, args) {
        const serializedArgs = args.map((arg) => arg instanceof element_1.UIElement ? arg.executeObj : arg);
        return this.cmd(command, script, serializedArgs);
    }
    async executeScript(script, args) {
        return this.executeBase('executeScript', script, args);
    }
    async executeAsyncScript(script, args) {
        return this.executeBase('executeAsyncScript', script, args);
    }
}
exports.Session = Session;
for (const command of Object.keys(protocolCommands_1.PROTOCOL_COMMANDS)) {
    if (COMMANDS_TO_SKIP.has(command) || command in element_1.ELEMENT_COMMANDS) {
        continue;
    }
    const methodName = COMMAND_ALIASES[command] ?? command;
    Session.prototype[methodName] = async function (...args) {
        return this.cmd(command, ...args);
    };
}
function attachToSession(sessionId, options, capabilities = {}) {
    const protocol = options.protocol ?? 'http';
    const hostname = options.hostname ?? 'localhost';
    const port = options.port ?? 4723;
    const rawPath = options.path ?? '/';
    const pathPrefix = rawPath === '/' ? '' : rawPath.replace(/\/+$/, '');
    const baseUrl = `${protocol}://${hostname}:${port}${pathPrefix}`;
    return new Session({ baseUrl, sessionId }, capabilities);
}
