"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WaitUntilFindStrategy = void 0;
const messaging_1 = require("@mablhq-internal/runtime/core/messaging/messaging");
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const execution_1 = require("@mablhq-internal/runtime/execution");
const FindStrategy_1 = __importDefault(require("./FindStrategy"));
const DEFAULT_POLL_PERIOD_MS = 500;
class WaitUntilFindStrategy extends FindStrategy_1.default {
    findStrategy;
    constructor(findStrategy) {
        super();
        this.findStrategy = findStrategy;
    }
    async findElement(driver, mobileExecutionContext, findDescriptor, isShortCircuited) {
        let findResult;
        const findStartTimeMs = (0, mablscriptFind_1.getNowInMillis)();
        const findTimeoutMs = this.getWaitTimeoutMs(findDescriptor);
        mobileExecutionContext.log.debug(`Waiting up to ${findTimeoutMs}ms for element to appear.`, {
            executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
        });
        do {
            try {
                const currentFindResult = await this.findStrategy.findElement(driver, mobileExecutionContext, findDescriptor, isShortCircuited);
                const validCandidates = this.getValidCandidates(findDescriptor, currentFindResult);
                if (currentFindResult &&
                    !!validCandidates.length &&
                    validCandidates[0].elementReference) {
                    findResult = {
                        ...currentFindResult,
                        elementReference: validCandidates[0].elementReference,
                        scoredCandidates: validCandidates,
                    };
                    mobileExecutionContext.log.debug(`Configure find filtered ${currentFindResult.scoredCandidates.length} candidates to ${validCandidates.length}.`, {
                        executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
                    });
                }
                const elapsedTimeMs = (0, mablscriptFind_1.getNowInMillis)() - findStartTimeMs;
                if (!!findResult) {
                    mobileExecutionContext.log.debug(`Found element after ${elapsedTimeMs}ms.`, {
                        executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
                    });
                    return findResult;
                }
                const hasExceededTimeout = elapsedTimeMs > findTimeoutMs;
                if (hasExceededTimeout) {
                    mobileExecutionContext.log.debug(`Timed out waiting for the element to appear.`, {
                        executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
                    });
                    break;
                }
            }
            catch (e) {
                mobileExecutionContext.log.debug(`Error during find iteration`, e);
            }
            await this.sleep(DEFAULT_POLL_PERIOD_MS);
        } while (!findResult &&
            !isShortCircuited() &&
            (0, mablscriptFind_1.getNowInMillis)() - findStartTimeMs < findTimeoutMs);
        return findResult;
    }
    isApplicable(findDescriptor) {
        return (0, mablscriptFind_1.findIsWaitUntil)(findDescriptor.findTarget);
    }
    getName() {
        return 'WaitUntilFindStrategy';
    }
    getWaitTimeoutMs(findDescriptor) {
        return ((0, mablscriptFind_1.getWaitUntilTimeoutMs)(findDescriptor.findTarget) ?? execution_1.FIND_TIMEOUT_MILLIS);
    }
    getValidCandidates(findDescriptor, findResult) {
        const scoredCandidates = findResult?.scoredCandidates;
        if (!scoredCandidates?.length) {
            return [];
        }
        if (!(0, mablscriptFind_1.findIsWaitUntil)(findDescriptor.findTarget)) {
            return scoredCandidates;
        }
        const propertyPreferences = findDescriptor.findTarget.configuration?.propertyPreferences;
        if (!propertyPreferences) {
            return scoredCandidates;
        }
        const validCandidates = scoredCandidates
            .filter((candidate) => Object.entries(propertyPreferences).every(([property, preference]) => {
            if (!preference.intended) {
                return true;
            }
            const expectedValue = preference.value;
            const candidateValue = candidate.selector[property]?.toString();
            return (0, mablscriptFind_1.compareStrings)(expectedValue, candidateValue, preference.comparator);
        }))
            .sort((a, b) => b.score - a.score);
        return validCandidates;
    }
}
exports.WaitUntilFindStrategy = WaitUntilFindStrategy;
