window.ls.filter
  .add("avatar", function ($value, element) {
    if (!$value) {
      return "";
    }

    let size = element.dataset["size"] || 80;
    let name = $value.name || $value || "";

    name = (typeof name !== 'string') ? '--' : name;

    return def =
      "/v1/avatars/initials?project=console" +
      "&name=" +
      encodeURIComponent(name) +
      "&width=" +
      size +
      "&height=" +
      size;
  })
  .add("selectedCollection", function ($value, router) {
    return $value === router.params.collectionId ? "selected" : "";
  })
  .add("selectedDocument", function ($value, router) {
    return $value === router.params.documentId ? "selected" : "";
  })
  .add("localeString", function ($value) {
    $value = parseInt($value);
    return !Number.isNaN($value) ? $value.toLocaleString() : "";
  })
  .add("date", function ($value, date) {
    return $value ? date.format("Y-m-d", $value) : "";
  })
  .add("dateTime", function ($value, date) {
    return $value ? date.format("Y-m-d H:i", $value) : "";
  })
  .add("dateText", function ($value, date) {
    return $value ? date.format("d M Y", $value) : "";
  })
  .add("timeSince", function ($value) {
    $value = $value * 1000;

    let seconds = Math.floor((Date.now() - $value) / 1000);
    let unit = "second";
    let direction = "ago";

    if (seconds < 0) {
      seconds = -seconds;
      direction = "from now";
    }

    let value = seconds;

    if (seconds >= 31536000) {
      value = Math.floor(seconds / 31536000);
      unit = "year";
    }
    else if (seconds >= 86400) {
      value = Math.floor(seconds / 86400);
      unit = "day";
    }
    else if (seconds >= 3600) {
      value = Math.floor(seconds / 3600);
      unit = "hour";
    }
    else if (seconds >= 60) {
      value = Math.floor(seconds / 60);
      unit = "minute";
    }

    if (value != 1) {
      unit = unit + "s";
    }

    return value + " " + unit + " " + direction;
  })
  .add("ms2hum", function ($value) {
    let temp = $value;
    const years = Math.floor(temp / 31536000),
      days = Math.floor((temp %= 31536000) / 86400),
      hours = Math.floor((temp %= 86400) / 3600),
      minutes = Math.floor((temp %= 3600) / 60),
      seconds = temp % 60;

    if (days || hours || seconds || minutes) {
      return (
        (years ? years + "y " : "") +
        (days ? days + "d " : "") +
        (hours ? hours + "h " : "") +
        (minutes ? minutes + "m " : "") +
        Number.parseFloat(seconds).toFixed(0) +
        "s"
      );
    }

    return "< 1s";
  })
  .add("seconds2hum", function ($value) {

    var seconds = ($value).toFixed(3);

    var minutes = ($value / (60)).toFixed(1);

    var hours = ($value / (60 * 60)).toFixed(1);

    var days = ($value / (60 * 60 * 24)).toFixed(1);

    if (seconds < 60) {
      return seconds + "s";
    } else if (minutes < 60) {
      return minutes + "m";
    } else if (hours < 24) {
      return hours + "h";
    } else {
      return days + "d"
    }
  })
  .add("markdown", function ($value, markdown) {
    return markdown.render($value);
  })
  .add("pageCurrent", function ($value, env) {
    return Math.ceil(parseInt($value || 0) / env.PAGING_LIMIT) + 1;
  })
  .add("pageTotal", function ($value, env) {
    let total = Math.ceil(parseInt($value || 0) / env.PAGING_LIMIT);
    return total ? total : 1;
  })
  .add("humanFileSize", function ($value) {
    if (!$value) {
      return 0;
    }

    let thresh = 1000;

    if (Math.abs($value) < thresh) {
      return $value;
    }

    let units = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
    let u = -1;

    do {
      $value /= thresh;
      ++u;
    } while (Math.abs($value) >= thresh && u < units.length - 1);

    return $value.toFixed(1);
  })
  .add("humanFileUnit", function ($value) {
    if (!$value) {
      return '';
    }

    let thresh = 1000;

    if (Math.abs($value) < thresh) {
      return 'B';
    }

    let units = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
    let u = -1;

    do {
      $value /= thresh;
      ++u;
    } while (Math.abs($value) >= thresh && u < units.length - 1);

    return units[u];
  })
  .add("statsTotal", function ($value) {
    if (!$value) {
      return 0;
    }

    $value = abbreviate($value, 0, false, false);

    return $value ?? "N/A";
  })
  .add("statsGetLast", function ($value) {
    if (!$value || $value.length < 1) {
      return 0;
    }

    return $value[$value.length - 1].value;
  })
  .add("statsGetTotal", function ($value) {
    if (!$value || $value.length < 1) {
      return 0;
    }

    return $value.reduce(function(value, object) { return value + object.value }, 0);
  })
  .add("isEmpty", function ($value) {
    return (!!$value);
  })
  .add("isEmptyObject", function ($value) {
    return ((Object.keys($value).length === 0 && $value.constructor === Object) || $value.length === 0)
  })
  .add("activeDomainsCount", function ($value) {
    let result = [];

    if (Array.isArray($value)) {
      result = $value.filter(function (node) {
        return (node.verification && node.certificateId);
      });
    }

    return result.length;
  })
  .add("documentAction", function (container) {
    let collection = container.get('project-collection');
    let document = container.get('project-document');

    if (collection && document && !document.$id) {
      return 'databases.createDocument';
    }

    return 'databases.updateDocument';
  })
  .add("documentSuccess", function (container) {
    let document = container.get('project-document');

    if (document && !document.$id) {
      return ',redirect';
    }

    return '';
  })
  .add("firstElement", function ($value) {
    if ($value && $value[0]) {
      return $value[0];
    }

    return $value;
  })
  .add("platformsLimit", function ($value) {
    return $value;
  })
  .add("limit", function ($value) {
    let postfix = ($value.length >= 50) ? '...' : '';
    return $value.substring(0, 50) + postfix;
    ;
  })
  .add("arraySentence", function ($value) {
    if (!Array.isArray($value)) {
      return '';
    }

    return $value.join(", ").replace(/,\s([^,]+)$/, ' and $1');
  })
  .add("runtimeName", function ($value, env) {
    if (env && env.RUNTIMES && env.RUNTIMES[$value]) {
      return env.RUNTIMES[$value].name;
    }

    return '';
  })
  .add("runtimeLogo", function ($value, env) {
    if (env && env.RUNTIMES && env.RUNTIMES[$value]) {
      return env.RUNTIMES[$value].logo;
    }

    return '';
  })
  .add("runtimeVersion", function ($value, env) {
    if (env && env.RUNTIMES && env.RUNTIMES[$value]) {
      return env.RUNTIMES[$value].version;
    }

    return '';
  })
  .add("indexAttributes", function ($value) {
    let output = '';

    for (let i = 0; i < $value.attributes.length; i++) {
      output += $value.attributes[i] + ' (' + $value.orders[i] + '), '
    }
    return output.slice(0, -2);
  })
  .add("collectionAttributes", function ($value) {
    if (!Array.isArray($value)) {
      return [];
    }

    $value.unshift({
      $id: '$id'
    });

    return $value;
  })
  .add("documentAttribute", function ($value, attribute) {
    if (attribute.key in $value) {
      return $value[attribute.key];
    }

    return null;
  })
  .add("accessProject", function ($value, router) {
    return ($value && $value.hasOwnProperty(router.params.project)) ? $value[router.params.project] : 0;
  })
  .add("first", function ($value) {
    return $value[0].$id;
  })
  .add("last", function ($value) {
    return $value[$value.length - 1].$id;
  })
  ;

function abbreviate(number, maxPlaces, forcePlaces, forceLetter) {
  number = Number(number);
  forceLetter = forceLetter || false;
  if (forceLetter !== false) {
    return annotate(number, maxPlaces, forcePlaces, forceLetter);
  }
  let abbr;
  if (number >= 1e12) {
    abbr = "T";
  } else if (number >= 1e9) {
    abbr = "B";
  } else if (number >= 1e6) {
    abbr = "M";
  } else if (number >= 1e3) {
    abbr = "K";
  } else {
    abbr = "";
  }
  return annotate(number, maxPlaces, forcePlaces, abbr);
}

function annotate(number, maxPlaces, forcePlaces, abbr) {
  // set places to false to not round
  let rounded = 0;
  switch (abbr) {
    case "T":
      rounded = number / 1e12;
      break;
    case "B":
      rounded = number / 1e9;
      break;
    case "M":
      rounded = number / 1e6;
      break;
    case "K":
      rounded = number / 1e3;
      break;
    case "":
      rounded = number;
      break;
  }
  if (maxPlaces !== false) {
    let test = new RegExp("\\.\\d{" + (maxPlaces + 1) + ",}$");
    if (test.test("" + rounded)) {
      rounded = rounded.toFixed(maxPlaces);
    }
  }
  if (forcePlaces !== false) {
    rounded = Number(rounded).toFixed(forcePlaces);
  }
  return rounded + abbr;
}
