import { liveQuery, Dexie } from 'dexie';
import React from 'react';

function useObservable(observableFactory, arg2, arg3) {
    // Resolve vars from overloading variants of this function:
    var deps;
    var defaultResult;
    if (typeof observableFactory === 'function') {
        deps = arg2 || [];
        defaultResult = arg3;
    }
    else {
        deps = [];
        defaultResult = arg2;
    }
    // Create a ref that keeps the state we need
    var monitor = React.useRef({
        hasResult: false,
        result: defaultResult,
        error: null,
    });
    // We control when component should rerender. Make triggerUpdate
    // as examplified on React's docs at:
    // https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate
    var _a = React.useReducer(function (x) { return x + 1; }, 0); _a[0]; var triggerUpdate = _a[1];
    // Memoize the observable based on deps
    var observable = React.useMemo(function () {
        // Make it remember previous subscription's default value when
        // resubscribing.
        var observable = typeof observableFactory === 'function'
            ? observableFactory()
            : observableFactory;
        if (!observable || typeof observable.subscribe !== 'function') {
            if (observableFactory === observable) {
                throw new TypeError("Given argument to useObservable() was neither a valid observable nor a function.");
            }
            else {
                throw new TypeError("Observable factory given to useObservable() did not return a valid observable.");
            }
        }
        if (!monitor.current.hasResult &&
            typeof window !== 'undefined' // Don't do this in SSR
        ) {
            // Optimize for BehaviorSubject and other observables implementing getValue():
            if (typeof observable.hasValue !== 'function' || observable.hasValue()) {
                if (typeof observable.getValue === 'function') {
                    monitor.current.result = observable.getValue();
                    monitor.current.hasResult = true;
                }
                else {
                    // Find out if the observable has a current value: try get it by subscribing and
                    // unsubscribing synchronously
                    var subscription = observable.subscribe(function (val) {
                        monitor.current.result = val;
                        monitor.current.hasResult = true;
                    });
                    // Unsubscribe directly. We only needed any synchronous value if it was possible.
                    if (typeof subscription === 'function') {
                        subscription();
                    }
                    else {
                        subscription.unsubscribe();
                    }
                }
            }
        }
        return observable;
    }, deps);
    // Integrate with react devtools:
    React.useDebugValue(monitor.current.result);
    // Subscribe to the observable
    React.useEffect(function () {
        var subscription = observable.subscribe(function (val) {
            var current = monitor.current;
            if (current.error !== null || current.result !== val) {
                current.error = null;
                current.result = val;
                current.hasResult = true;
                triggerUpdate();
            }
        }, function (err) {
            var current = monitor.current;
            if (current.error !== err) {
                current.error = err;
                triggerUpdate();
            }
        });
        return typeof subscription === 'function'
            ? subscription // Support observables that return unsubscribe directly
            : subscription.unsubscribe.bind(subscription);
    }, deps);
    // Throw if observable has emitted error so that
    // an ErrorBoundrary can catch it
    if (monitor.current.error)
        throw monitor.current.error;
    // Return the current result
    return monitor.current.result;
}

function useLiveQuery(querier, deps, defaultResult) {
    return useObservable(function () { return liveQuery(querier); }, deps || [], defaultResult);
}

function usePermissions(firstArg, table, obj) {
    if (!firstArg)
        throw new TypeError("Invalid arguments to usePermissions(): undefined or null");
    var db;
    if (arguments.length >= 3) {
        if (!('transaction' in firstArg)) {
            // Using ducktyping instead of instanceof in case there are multiple Dexie modules in app.
            // First arg is  ensures first arg is a Dexie instance
            throw new TypeError("Invalid arguments to usePermission(db, table, obj): 1st arg must be a Dexie instance");
        }
        if (typeof table !== 'string')
            throw new TypeError("Invalid arguments to usePermission(db, table, obj): 2nd arg must be string");
        if (!obj || typeof obj !== 'object')
            throw new TypeError("Invalid arguments to usePermission(db, table, obj): 3rd arg must be an object");
        db = firstArg;
    }
    else {
        if (firstArg instanceof Dexie)
            throw new TypeError("Invalid arguments to usePermission(db, table, obj): Missing table and obj arguments.");
        if (typeof firstArg.table === 'function' &&
            typeof firstArg.db === 'object') {
            db = firstArg.db;
            obj = firstArg;
            table = firstArg.table();
        }
        else {
            throw new TypeError("Invalid arguments to usePermissions(). " +
                "Expected usePermissions(entity: DexieCloudEntity) or " +
                "usePermissions(db: Dexie, table: string, obj: DexieCloudObject)");
        }
    }
    if (!('cloud' in db))
        throw new Error("usePermissions() is only for Dexie Cloud but there's no dexie-cloud-addon active in given db.");
    if (!('permissions' in db.cloud))
        throw new Error("usePermissions() requires a newer version of dexie-cloud-addon. Please upgrade it.");
    return useObservable(
    // @ts-ignore
    function () { return db.cloud.permissions(obj, table); }, [obj.realmId, obj.owner, table]);
}

export { useLiveQuery, useObservable, usePermissions };
//# sourceMappingURL=dexie-react-hooks.mjs.map
