const cache = new Map();
const key = 'hulk_epfitf_telephone_geoIpLookup';

async function ipapi(): Promise<string> {
	const response = await fetch('//ipapi.co/json');
	if (!response.ok) {
		throw response;
	}
	const data = await response.json();
	return data?.country_code ?? '';
}

async function geojs(): Promise<string> {
	const response = await fetch('//get.geojs.io/v1/ip/country.json');
	if (!response.ok) {
		throw response;
	}
	const data = await response.json();
	return data?.country ?? '';
}

async function ipGuide(): Promise<string> {
	const response = await fetch('//ip.guide');
	if (!response.ok) {
		throw response;
	}
	const data = await response.json();
	return data?.network?.autonomous_system?.country ?? '';
}

async function bigdatacloud(): Promise<string> {
	const response = await fetch('//api.bigdatacloud.net/data/reverse-geocode-client');
	if (!response.ok) {
		throw response;
	}
	const data = await response.json();
	return data?.countryCode ?? '';
}

async function lookup(defaultCode: string): Promise<string> {
	return ipapi()
		.then(value => value.toLowerCase())
		.catch(() => geojs())
		.then(value => value.toLowerCase())
		.catch(() => ipGuide())
		.then(value => value.toLowerCase())
		.catch(() => bigdatacloud())
		.then(value => value.toLowerCase())
		.catch(() => defaultCode.toLowerCase());
}

function geoIpLookup(defaultCode: string) {
	if (!cache.has(key)) {
		cache.set(key, lookup(defaultCode));
	}
	return cache.get(key);
}

export default geoIpLookup
