const waitUntil = (subject, checkFunction, originalOptions = {}) => {
    if (!(checkFunction instanceof Function)) {
        throw new Error(
            '`checkFunction` parameter should be a function. Found: ' + checkFunction
        );
    }

    const defaultOptions = {
        // base options
        interval: 200,
        timeout: 5000,
        errorMsg: 'Timed out retrying',

        // log options
        description: 'waitUntil',
        log: true,
        customMessage: undefined,
        logger: Cypress.log,
        verbose: false,
        customCheckMessage: undefined,
    };
    const options = { ...defaultOptions, ...originalOptions };

    // filter out a falsy passed "customMessage" value
    options.customMessage = [options.customMessage, originalOptions].filter(Boolean);

    const endTime = Date.now() + options.timeout;

    const check = (result) => {
        if (result) {
            return result;
        }
        if (Date.now() >= endTime) {
            const msg =
                options.errorMsg instanceof Function
                    ? options.errorMsg(result, options)
                    : options.errorMsg;
            throw new Error(msg);
        }
        cy.wait(options.interval, { log: false }).then(() => {
            return resolveValue();
        });
    };

    const resolveValue = () => {
        const result = checkFunction(subject);

        const isAPromise = Boolean(result && result.then);
        if (isAPromise) {
            return result.then(check);
        } else {
            return check(result);
        }
    };

    return resolveValue();
};

export default waitUntil;