/* global L, log -- eslint */

/**
 * @file Contain misc functions to get portal info
 * @module portal_data
 */

/**
 * Search through the links data for all that link from and to a portal. Returns an object with separate lists of in
 * and out links. May or may not be as accurate as the portal details, depending on how much data the API returns.
 *
 * @function getPortalLinks
 * @param {string} guid - The GUID of the portal to search for links.
 * @returns {Object} An object containing arrays of incoming ('in') and outgoing ('out') link GUIDs.
 */
window.getPortalLinks = function (guid) {
  var links = { in: [], out: [] };

  $.each(window.links, function (g, l) {
    var d = l.options.data;

    if (d.oGuid === guid) {
      links.out.push(g);
    }
    if (d.dGuid === guid) {
      links.in.push(g);
    }
  });

  return links;
};

/**
 * Counts the total number of links (both incoming and outgoing) for a specified portal.
 *
 * @function getPortalLinksCount
 * @param {string} guid - The GUID of the portal.
 * @returns {number} The total number of links for the portal.
 */
window.getPortalLinksCount = function (guid) {
  var links = window.getPortalLinks(guid);
  return links.in.length + links.out.length;
};

/**
 * Searches through the fields for all fields that reference a specified portal.
 *
 * @function getPortalFields
 * @param {string} guid - The GUID of the portal to search for fields.
 * @returns {Array} An array containing the GUIDs of fields associated with the portal.
 */
window.getPortalFields = function (guid) {
  var fields = [];

  $.each(window.fields, function (g, f) {
    var d = f.options.data;

    if (d.points[0].guid === guid || d.points[1].guid === guid || d.points[2].guid === guid) {
      fields.push(g);
    }
  });

  return fields;
};

/**
 * Counts the total number of fields associated with a specified portal.
 *
 * @function getPortalFieldsCount
 * @param {string} guid - The GUID of the portal.
 * @returns {number} The total number of fields associated with the portal.
 */
window.getPortalFieldsCount = function (guid) {
  var fields = window.getPortalFields(guid);
  return fields.length;
};

/**
 * Zooms the map to a specific portal and shows its details if available.
 *
 * @function zoomToAndShowPortal
 * @param {string} guid - The globally unique identifier of the portal.
 * @param {L.LatLng|number[]} latlng - The latitude and longitude of the portal.
 */
window.zoomToAndShowPortal = function (guid, latlng) {
  window.map.setView(latlng, window.DEFAULT_ZOOM);
  // if the data is available, render it immediately. Otherwise defer
  // until it becomes available.
  if (window.portals[guid]) window.renderPortalDetails(guid);
  else window.selectPortalWhenLoadedByGuid(guid);
};

/**
 * Selects a portal by its latitude and longitude.
 *
 * @function selectPortalByLatLng
 * @param {number|Array|L.LatLng} lat - The latitude of the portal
 *                                      or an array or L.LatLng object containing both latitude and longitude.
 * @param {number} [lng] - The longitude of the portal.
 */
window.selectPortalByLatLng = function (lat, lng) {
  if (lng === undefined && lat instanceof Array) {
    lng = lat[1];
    lat = lat[0];
  } else if (lng === undefined && lat instanceof L.LatLng) {
    lng = lat.lng;
    lat = lat.lat;
  }
  for (var guid in window.portals) {
    var latlng = window.portals[guid].getLatLng();
    if (latlng.lat === lat && latlng.lng === lng) {
      window.renderPortalDetails(guid);
      return;
    }
  }

  // not currently visible
  const ll = new L.LatLng(lat, lng);
  window.selectPortalWhenLoadedByLatLng(ll);
  window.map.setView(ll, window.DEFAULT_ZOOM);
};

let urlPortalLL;
/**
 * Select a portal when it appears on the map
 *
 * @function
 * @name selectPortalWhenLoadedByLatLng
 * @param {L.LatLng} latLng - the location of the portal
 */
window.selectPortalWhenLoadedByLatLng = (latLng) => {
  if (urlPortalLL === undefined) {
    window.addHook('portalAdded', testPortalLatLng);
  }

  urlPortalLL = latLng;
  window.urlPortalLL = latLng; // @deprecated
};

const testPortalLatLng = (data) => {
  if (data.portal.getLatLng().equals(urlPortalLL)) {
    log.log(`urlPortalLL ${urlPortalLL.toString()} matches portal GUID ${data.portal.options.guid}`);
    window.selectedPortal = data.portal.options.guid;
    window.renderPortalDetails(window.selectedPortal, true);
    urlPortalLL = undefined;
    window.urlPortalLL = undefined; // @deprecated
  }

  if (!urlPortalLL) window.removeHook('portalAdded', testPortalLatLng);
};

let urlPortal;
/**
 * Select a portal when it appears on the map
 *
 * @function
 * @name selectPortalWhenLoadedByGuid
 * @param {string} guid - the guid of the portal
 */
window.selectPortalWhenLoadedByGuid = (guid) => {
  if (urlPortal === undefined) {
    window.addHook('portalAdded', testPortalGuid);
  }

  urlPortal = guid;
  window.urlPortal = guid; // @deprecated
};

const testPortalGuid = (data) => {
  if (data.portal.options.guid === urlPortal) {
    log.log(`urlPortal GUID ${window.urlPortal} found - selecting...`);
    window.selectedPortal = urlPortal;
    window.renderPortalDetails(window.selectedPortal, true);
    urlPortal = undefined;
    window.urlPortal = undefined; // @deprecated
  }

  if (!urlPortal) window.removeHook('portalAdded', testPortalGuid);
};

/**
 * Finds a portal GUID by its position. Searches through currently rendered portals.
 * Note: this includes fields and links.
 *
 * @function
 * @name findPortalGuidByPositionE6
 * @param {number} latE6 - The latitude in E6 format.
 * @param {number} lngE6 - The longitude in E6 format.
 * @returns {string|null} The GUID of the portal at the specified location, or null if not found.
 */
window.findPortalGuidByPositionE6 = function (latE6, lngE6) {
  const portal = Object.values(window.portals).find((p) => p.options.data.latE6 === latE6 && p.options.data.lngE6 === lngE6);
  return portal?.options.data.guid ?? null;
};