let shim = {};

shim.isNode = () => {
	if (typeof process === 'undefined') return false;
	if (shim.isElectron()) return true;
	return process.title == 'node';
};

shim.isReactNative = () => {
	return !shim.isNode();
};

// https://github.com/cheton/is-electron
shim.isElectron = () => {
    // Renderer process
    if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {
        return true;
    }

    // Main process
    if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {
        return true;
    }

    // Detect the user agent when the `nodeIntegration` option is set to true
    if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
        return true;
    }

    return false;
}

// Node requests can go wrong is so many different ways and with so
// many different error messages... This handler inspects the error
// and decides whether the request can safely be repeated or not.
function fetchRequestCanBeRetried(error) {
    if (!error) return false;

    // Unfortunately the error 'Network request failed' doesn't have a type
    // or error code, so hopefully that message won't change and is not localized
    if (error.message == 'Network request failed') return true;

    // request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up"
    if (error.code == 'ECONNRESET') return true;

    // OneDrive (or Node?) sometimes sends back a "not found" error for resources
    // that definitely exist and in this case repeating the request works.
    // Error is:
    // request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443      
    if (error.code == 'ENOTFOUND') return true;

    // network timeout at: https://public-ch3302...859f9b0e3ab.md
    if (error.message && error.message.indexOf('network timeout') === 0) return true;

    // name: 'FetchError',
    // message: 'request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443',
    // type: 'system',
    // errno: 'EAI_AGAIN',
    // code: 'EAI_AGAIN' } } reason: { FetchError: request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443
    //
    // It's a Microsoft error: "A temporary failure in name resolution occurred."
    if (error.code == 'EAI_AGAIN') return true;

    // request to https://public-...8fd8bc6bb68e9c4d17a.md failed, reason: connect ETIMEDOUT 204.79.197.213:443
    // Code: ETIMEDOUT
    if (error.code === 'ETIMEDOUT') return true;

    return false;
}

shim.fetchWithRetry = async function(fetchFn, options = null) {
    const { time } = require('lib/time-utils.js');

    if (!options) options = {};
    if (!options.timeout) options.timeout = 1000 * 120; // ms
    if (!('maxRetry' in options)) options.maxRetry = 5;

    let retryCount = 0;
    while (true) {
        try {
            const response = await fetchFn();
            return response;
        } catch (error) {
            if (fetchRequestCanBeRetried(error)) {
                retryCount++;
                if (retryCount > options.maxRetry) throw error;
                await time.sleep(retryCount * 3);
            } else {
                throw error;
            }
        }
    }
}

shim.nativeFetch_ = typeof fetch !== 'undefined' ? fetch : null;
shim.fetch = () => { throw new Error('Not implemented'); }
shim.FormData = typeof FormData !== 'undefined' ? FormData : null;
shim.fs = null;
shim.FileApiDriverLocal = null;
shim.readLocalFileBase64 = (path) => { throw new Error('Not implemented'); }
shim.uploadBlob = () => { throw new Error('Not implemented'); }
shim.setInterval = function(fn, interval) {
	return setInterval(fn, interval);
}
shim.clearInterval = function(id) {
	return clearInterval(id);
}
shim.detectAndSetLocale = null;
shim.attachFileToNote = async (note, filePath) => {}

module.exports = { shim };