import Constants from 'expo-constants';
import { hasCustomScheme, resolveScheme } from './Schemes';
import { validateURL } from './validateURL';
function getHostUri() {
    if (Constants.expoConfig?.hostUri) {
        return Constants.expoConfig.hostUri;
    }
    else if (!hasCustomScheme()) {
        // we're probably not using up-to-date xdl, so just fake it for now
        // we have to remove the /--/ on the end since this will be inserted again later
        return removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
    }
    else {
        return null;
    }
}
function isExpoHosted() {
    const hostUri = getHostUri();
    return !!(hostUri &&
        (/^(.*\.)?(expo\.io|exp\.host|exp\.direct|expo\.test|expo\.dev)(:.*)?(\/.*)?$/.test(hostUri) ||
            Constants.expoGoConfig?.developer));
}
function removeScheme(url) {
    return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
}
function removePort(url) {
    return url.replace(/(?=([a-zA-Z0-9+.-]+:\/\/)?[^/]):\d+/, '');
}
function removeLeadingSlash(url) {
    return url.replace(/^\//, '');
}
function removeTrailingSlashAndQueryString(url) {
    return url.replace(/\/?\?.*$/, '');
}
function ensureLeadingSlash(input, shouldAppend) {
    const hasSlash = input.startsWith('/');
    if (hasSlash && !shouldAppend) {
        return input.substring(1);
    }
    else if (!hasSlash && shouldAppend) {
        return `/${input}`;
    }
    return input;
}
// @needsAudit
/**
 * Helper method for constructing a deep link into your app, given an optional path and set of query
 * parameters. Creates a URI scheme with two slashes by default.
 *
 * The scheme must be defined in the [app config](./../config/app) under `expo.scheme`
 * or `expo.{android,ios}.scheme`. Platform-specific schemes defined under `expo.{android,ios}.scheme`
 * take precedence over universal schemes defined under `expo.scheme`.
 *
 * # Examples
 * - Development and production builds: `<scheme>://path` - uses the optional `scheme` property if provided, and otherwise uses the first scheme defined by your app config
 * - Web (dev): `https://localhost:19006/path`
 * - Web (prod): `https://myapp.com/path`
 * - Expo Go (dev): `exp://128.0.0.1:8081/--/path`
 *
 * The behavior of this method in Expo Go for published updates is undefined and should not be relied upon.
 * The created URL in this case is neither stable nor predictable during the lifetime of the app.
 * If a stable URL is needed, for example in authorization callbacks, a build (or development build)
 * of your application should be used and the scheme provided.
 *
 * @param path Addition path components to append to the base URL.
 * @param namedParameters Additional options object.
 * @return A URL string which points to your app with the given deep link information.
 */
export function createURL(path, { scheme, queryParams = {}, isTripleSlashed = false } = {}) {
    const resolvedScheme = resolveScheme({ scheme });
    let hostUri = getHostUri() || '';
    if (hasCustomScheme() && isExpoHosted()) {
        hostUri = '';
    }
    if (path) {
        if (isExpoHosted() && hostUri) {
            path = `/--/${removeLeadingSlash(path)}`;
        }
        if (isTripleSlashed && !path.startsWith('/')) {
            path = `/${path}`;
        }
    }
    else {
        path = '';
    }
    // merge user-provided query params with any that were already in the hostUri
    // e.g. release-channel
    let queryString = '';
    const queryStringMatchResult = hostUri.match(/(.*)\?(.+)/);
    if (queryStringMatchResult) {
        hostUri = queryStringMatchResult[1];
        queryString = queryStringMatchResult[2];
        let paramsFromHostUri = {};
        try {
            paramsFromHostUri = Object.fromEntries(
            // @ts-ignore: [Symbol.iterator] is indeed, available on every platform.
            new URLSearchParams(queryString));
        }
        catch { }
        queryParams = {
            ...queryParams,
            ...paramsFromHostUri,
        };
    }
    queryString = new URLSearchParams(
    // For legacy purposes, we'll strip out the nullish values before creating the URL.
    Object.fromEntries(Object.entries(queryParams).filter(([, value]) => value != null))).toString();
    if (queryString) {
        queryString = `?${queryString}`;
    }
    hostUri = ensureLeadingSlash(hostUri, !isTripleSlashed);
    // URLSearchParams.stringify already encodes query parameters, so we only need to encode the remaining part of the URL.
    const encodedURI = encodeURI(`${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}`);
    return `${encodedURI}${queryString}`;
}
// @needsAudit
/**
 * Helper method for parsing out deep link information from a URL.
 * @param url A URL that points to the currently running experience (for example, an output of `Linking.createURL()`).
 * @return A `ParsedURL` object.
 */
export function parse(url) {
    validateURL(url);
    const queryParams = {};
    let path = null;
    let hostname = null;
    let scheme = null;
    try {
        const parsed = new URL(url);
        parsed.searchParams.forEach((value, key) => {
            queryParams[key] = decodeURIComponent(value);
        });
        path = parsed.pathname || null;
        hostname = parsed.hostname || null;
        scheme = parsed.protocol || null;
    }
    catch {
        path = url;
    }
    const hostUri = getHostUri() || '';
    const hostUriStripped = removePort(removeTrailingSlashAndQueryString(hostUri));
    if (scheme) {
        // Remove colon at end
        scheme = scheme.substring(0, scheme.length - 1);
    }
    if (path) {
        path = removeLeadingSlash(path);
        let expoPrefix = null;
        if (hostUriStripped) {
            const parts = hostUriStripped.split('/');
            expoPrefix = parts.slice(1).concat(['--/']).join('/');
        }
        if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {
            path = path.substring(expoPrefix.length);
            hostname = null;
        }
        else if (path.indexOf('+') > -1) {
            path = path.substring(path.indexOf('+') + 1);
        }
    }
    return {
        hostname,
        path,
        queryParams,
        scheme,
    };
}
//# sourceMappingURL=createURL.js.map