/**
 * Implements fast shallow verification of hostnames. This does not perform a
 * struct check on the content of labels (classes of Unicode characters, etc.)
 * but instead check that the structure is valid (number of labels, length of
 * labels, etc.).
 *
 * If you need stricter validation, consider using an external library.
 */

function isValidAscii(code: number): boolean {
  return (
    (code >= 97 && code <= 122) || (code >= 48 && code <= 57) || code > 127
  );
}

/**
 * Check if a hostname string is valid. It's usually a preliminary check before
 * trying to use getDomain or anything else.
 *
 * Beware: it does not check if the TLD exists.
 */
export default function (hostname: string): boolean {
  if (hostname.length > 255) {
    return false;
  }

  if (hostname.length === 0) {
    return false;
  }

  if (
    /*@__INLINE__*/ !isValidAscii(hostname.charCodeAt(0)) &&
    hostname.charCodeAt(0) !== 46 && // '.' (dot)
    hostname.charCodeAt(0) !== 95 // '_' (underscore)
  ) {
    return false;
  }

  // Validate hostname according to RFC
  let lastDotIndex = -1;
  let lastCharCode = -1;
  const len = hostname.length;

  for (let i = 0; i < len; i += 1) {
    const code = hostname.charCodeAt(i);
    if (code === 46 /* '.' */) {
      if (
        // Check that previous label is < 63 bytes long (64 = 63 + '.')
        i - lastDotIndex > 64 ||
        // Check that previous character was not already a '.'
        lastCharCode === 46 ||
        // Check that the previous label does not end with a '-' (dash)
        lastCharCode === 45 ||
        // Check that the previous label does not end with a '_' (underscore)
        lastCharCode === 95
      ) {
        return false;
      }

      lastDotIndex = i;
    } else if (
      !(/*@__INLINE__*/ (isValidAscii(code) || code === 45 || code === 95))
    ) {
      // Check if there is a forbidden character in the label
      return false;
    }

    lastCharCode = code;
  }

  return (
    // Check that last label is shorter than 63 chars
    len - lastDotIndex - 1 <= 63 &&
    // Check that the last character is an allowed trailing label character.
    // Since we already checked that the char is a valid hostname character,
    // we only need to check that it's different from '-'.
    lastCharCode !== 45
  );
}
