;

function getRandomSign() {
  return Math.random() > 0.5 ? -1 : 1;
}

function getRandomDegrees(around = 360) {
  // sign multiplied per a number between 0 and 360
  return getRandomSign() * Math.round(Math.random() * around);
}

/*
 * Get the correct model at some points from the JSON descriptor
 * @param: models Array Collection of objects with a reference to 3D models for the main caharacter
 * @param points Number Points to query the 3D model
 *  
 */
function getFpModel(models, points) {
  return _.find(_.orderBy(models, ['grows_at'], ['desc']), function(m) {
    return parseInt(points) >= m.grows_at;
  });
}

function getFruitBySlug(fruits, slug) {
	return _.find(fruits, function(f) {
		return slug == f.slug;
	});
}
/*
 * Appends a-asset-item nodes to A Frame Assets Library
 * @param: obj Object from API JSON
 * 
 */
function addAssetItem(obj, preload = true) {
	const doc = document;
	const item = doc.createElement('a-asset-item');
	item.setAttribute('src', obj.model_url);
	item.setAttribute('id', obj.slug);
	if(preload)
		item.setAttribute('preload', 'auto');
	
	return doc.querySelector('a-assets').appendChild(item);
}
/*
 * If there is an upcoming size or not
 */
function hasUpcoming(models, currentModel) {
  let upcomingModel = _.find(_.orderBy(models, ['grows_at'], ['desc']), function(m) {
    return (parseInt(currentModel.dataset.totalPoints) + POINTS_TO_GROW) >= m.grows_at;
  });
  
  return upcomingModel.slug !== currentModel.dataset.current ? upcomingModel : false;
}

/**
 * Adds fruit models from API to A-Frame Scene given the coords { latitude , longitude } or { latitude, longitude, altitude }
 */
async function addFruitsAround(sceneEl, coords) {
  // fruits come from WS
  let fruitsAt = await getFruitsAt(coords),
		amount = fruitsAt.fruits.length,
		vault = Vault.init('fruitpick'),
		descriptor;

	descriptor = vault.get('descriptor');
  
  if (amount > 0)
    gameBar.fruitsFound += amount;

	/*
		descriptor = vault.get('descriptor');
  
  if (amount > 0) {
    gameBar.fruitsFound += amount;	 
	if(vault.get('modelsLoaded') != '') {
		descriptor.fruits.forEach(addAssetItem);
		descriptor.character.sizes.forEach(addAssetItem);
		vault.save('modelsLoaded', true);
	}
  }
	*/

  
  if (window.verbose)
    gameBar.log(`at location: ${coords.latitude}, ${coords.longitude}`);
  
  for (let f in fruitsAt.fruits) {
    
    let fruitRef = fruitsAt.fruits[f],
      fruit = document.createElement('a-entity'),
      fruitModel = getFruitBySlug(descriptor.fruits, fruitRef.fruit.slug), // slug comes from WS, then fetched from catalog
      minScale = 0.75,
      maxScale = 1.25,
      scale = minScale + Math.round(Math.random() * (maxScale - minScale)),
      loc = {
        // latitude: navigator.onLine ? fruitRef.latitude : (Number(coords.latitude) + _.random(-0.001, 0.001)),
        // longitude: navigator.onLine ? fruitRef.longitude : (Number(coords.longitude) + _.random(-0.001, 0.001)),
        latitude: fruitRef.latitude,
        longitude: fruitRef.longitude
        //altitude: fruitRef.altitude
      };
    
    fruit.setAttribute('gps-new-entity-place', loc);
    fruit.setAttribute('scale', { x: scale, y: scale, z: scale });
    fruit.setAttribute('rotation', { x: getRandomDegrees(), y: getRandomDegrees(), z: getRandomDegrees() });
    
    // @todo: materials rendering and DB model storage
    
    fruit.setAttribute(fruitModel.model_loader, '#' + fruitModel.slug);
    
    if (window.debug) {
      fruit.addEventListener('model-loaded', function(ev) {
        console.log('Model loaded: ' + fruitModel.name);
      });
      fruit.addEventListener('model-error', function(ev) {
        console.log('Error loading: ' + fruitModel.name);
      });
    }
    
    fruit.dataset.points = fruitModel.points;
    fruit.setAttribute('pickable', true);
    fruit.setAttribute('obb-collider', true);
    fruit.setAttribute('sphere-collider', true);
    fruit.setAttribute('browser_uuid', crypto.randomUUID());
    fruit.setAttribute('id', fruitRef.id);
    
    fruit.setAttribute('shadow', true);
    sceneEl.appendChild(fruit);
    
    if (window.verbose)
      gameBar.log(loc.latitude + ',' + loc.longitude);
  }
  
  return fruitsAt;
}

// async caller to API
async function getFruitsAt(position) {
  
  const url = getFruitsUrl(position),
    response = await fetch(url);
  
  if (!response.ok) {
    gameBar.log(`No connection to fruits server, retrying... ${response.status}`);
    throw new Error(response.status);
    return;
  }
  
  return await response.json();
  
}

// If network status is online, return API URL, otherwise local JSON reference
function getFruitsUrl(position) {
  const user = vault.get('user', false);

  if(user != false && 'browser_uuid' in user)
	position.browser_uuid = user.browser_uuid;

	position.user_agent = navigator.userAgent;

  return navigator.onLine ?
    `${window.apiUrl}/fruits/at-location?${new URLSearchParams(position)}` :
    `${window.apiUrl}-${_.random(0, 5)}.json`;
}

/**
 * GPS Position validator
 */
function isValidPosition(coords) {
  let minPrecision = 1,
    maxPrecision = 20,
    minLat = -200,
    maxLat = 200,
    minLng = -200,
    maxLng = 200
  
  ;
  
  for (let k in ['latitude', 'longitude']) {
    if (!k in coords)
      return false;
  }
  // Betweens
  
  if (
    coords.latitude < minLat ||
    coords.latitude > maxLat ||
    coords.longitude < minLng ||
    coords.longitude > maxLng
  )
    return false;
  
  let latSplit = coords.latitude.split('.'),
    lngSplit = coords.longitude.split('.');
  
  if (
    // Too far coordinates not valid
    latSplit.length === 1 ||
    lngSplit.length === 1
    
    
    // Precision
    ||
    (parseStr(latSplit[1]).length < minPrecision) ||
    (parseStr(latSplit[1]).length > maxPrecision) ||
    (parseStr(lngSplit[1]).length < minPrecision) ||
    (parseStr(lngSplit[1]).length > maxPrecision)
  )
    return false;
  
  
  return true;
}