import { AppState, Linking, Platform } from 'react-native';
import { UnavailabilityError } from '@unimodules/core';
import ExponentWebBrowser from './ExpoWebBrowser';
const emptyCustomTabsPackages = {
    defaultBrowserPackage: undefined,
    preferredBrowserPackage: undefined,
    browserPackages: [],
    servicePackages: [],
};
export async function getCustomTabsSupportingBrowsersAsync() {
    if (!ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync) {
        throw new UnavailabilityError('WebBrowser', 'getCustomTabsSupportingBrowsersAsync');
    }
    if (Platform.OS !== 'android') {
        return emptyCustomTabsPackages;
    }
    else {
        return await ExponentWebBrowser.getCustomTabsSupportingBrowsersAsync();
    }
}
export async function warmUpAsync(browserPackage) {
    if (!ExponentWebBrowser.warmUpAsync) {
        throw new UnavailabilityError('WebBrowser', 'warmUpAsync');
    }
    if (Platform.OS !== 'android') {
        return {};
    }
    else {
        return await ExponentWebBrowser.warmUpAsync(browserPackage);
    }
}
export async function mayInitWithUrlAsync(url, browserPackage) {
    if (!ExponentWebBrowser.mayInitWithUrlAsync) {
        throw new UnavailabilityError('WebBrowser', 'mayInitWithUrlAsync');
    }
    if (Platform.OS !== 'android') {
        return {};
    }
    else {
        return await ExponentWebBrowser.mayInitWithUrlAsync(url, browserPackage);
    }
}
export async function coolDownAsync(browserPackage) {
    if (!ExponentWebBrowser.coolDownAsync) {
        throw new UnavailabilityError('WebBrowser', 'coolDownAsync');
    }
    if (Platform.OS !== 'android') {
        return {};
    }
    else {
        return await ExponentWebBrowser.coolDownAsync(browserPackage);
    }
}
export async function openBrowserAsync(url, browserParams = {}) {
    if (!ExponentWebBrowser.openBrowserAsync) {
        throw new UnavailabilityError('WebBrowser', 'openBrowserAsync');
    }
    return await ExponentWebBrowser.openBrowserAsync(url, browserParams);
}
export function dismissBrowser() {
    if (!ExponentWebBrowser.dismissBrowser) {
        throw new UnavailabilityError('WebBrowser', 'dismissBrowser');
    }
    ExponentWebBrowser.dismissBrowser();
}
export async function openAuthSessionAsync(url, redirectUrl) {
    if (_authSessionIsNativelySupported()) {
        if (!ExponentWebBrowser.openAuthSessionAsync) {
            throw new UnavailabilityError('WebBrowser', 'openAuthSessionAsync');
        }
        return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl);
    }
    else {
        return _openAuthSessionPolyfillAsync(url, redirectUrl);
    }
}
export function dismissAuthSession() {
    if (_authSessionIsNativelySupported()) {
        if (!ExponentWebBrowser.dismissAuthSession) {
            throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
        }
        ExponentWebBrowser.dismissAuthSession();
    }
    else {
        if (!ExponentWebBrowser.dismissBrowser) {
            throw new UnavailabilityError('WebBrowser', 'dismissAuthSession');
        }
        ExponentWebBrowser.dismissBrowser();
    }
}
/* iOS <= 10 and Android polyfill for SFAuthenticationSession flow */
function _authSessionIsNativelySupported() {
    if (Platform.OS === 'android') {
        return false;
    }
    const versionNumber = parseInt(String(Platform.Version), 10);
    return versionNumber >= 11;
}
let _redirectHandler = null;
/*
 * openBrowserAsync on Android doesn't wait until closed, so we need to polyfill
 * it with AppState
 */
// Store the `resolve` function from a Promise to fire when the AppState
// returns to active
let _onWebBrowserCloseAndroid = null;
function _onAppStateChangeAndroid(state) {
    if (state === 'active' && _onWebBrowserCloseAndroid) {
        _onWebBrowserCloseAndroid();
    }
}
async function _openBrowserAndWaitAndroidAsync(startUrl) {
    let appStateChangedToActive = new Promise(resolve => {
        _onWebBrowserCloseAndroid = resolve;
        AppState.addEventListener('change', _onAppStateChangeAndroid);
    });
    let result = { type: 'cancel' };
    let { type } = await openBrowserAsync(startUrl);
    if (type === 'opened') {
        await appStateChangedToActive;
        result = { type: 'dismiss' };
    }
    AppState.removeEventListener('change', _onAppStateChangeAndroid);
    _onWebBrowserCloseAndroid = null;
    return result;
}
async function _openAuthSessionPolyfillAsync(startUrl, returnUrl) {
    if (_redirectHandler) {
        throw new Error(`The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`);
    }
    if (_onWebBrowserCloseAndroid) {
        throw new Error(`WebBrowser is already open, only one can be open at a time`);
    }
    try {
        if (Platform.OS === 'android') {
            return await Promise.race([
                _openBrowserAndWaitAndroidAsync(startUrl),
                _waitForRedirectAsync(returnUrl),
            ]);
        }
        else {
            return await Promise.race([openBrowserAsync(startUrl), _waitForRedirectAsync(returnUrl)]);
        }
    }
    finally {
        // We can't dismiss the browser on Android, only call this when it's available.
        // Users on Android need to manually press the 'x' button in Chrome Custom Tabs, sadly.
        if (ExponentWebBrowser.dismissBrowser) {
            ExponentWebBrowser.dismissBrowser();
        }
        _stopWaitingForRedirect();
    }
}
function _stopWaitingForRedirect() {
    if (!_redirectHandler) {
        throw new Error(`The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`);
    }
    Linking.removeEventListener('url', _redirectHandler);
    _redirectHandler = null;
}
function _waitForRedirectAsync(returnUrl) {
    return new Promise(resolve => {
        _redirectHandler = (event) => {
            if (event.url.startsWith(returnUrl)) {
                resolve({ url: event.url, type: 'success' });
            }
        };
        Linking.addEventListener('url', _redirectHandler);
    });
}
//# sourceMappingURL=WebBrowser.js.map