/* https://github.com/sindresorhus/filename-reserved-regex */

function filenameReservedRegex() {
  return /[<>:"/\\|?*\u0000-\u001F]/g; // eslint-disable-line no-control-regex
}

function windowsReservedNameRegex() {
  return /^(con|prn|aux|nul|com\d|lpt\d)$/i;
}

/* https://github.com/sindresorhus/filenamify */

// Doesn't make sense to have longer filenames
const MAX_FILENAME_LENGTH = 100;

const reRelativePath = /^\.+(\\|\/)|^\.+$/;
const reTrailingPeriods = /\.+$/;

function filenamify(string, options = {}) {
  const reControlChars = /[\u0000-\u001F\u0080-\u009F]/g; // eslint-disable-line no-control-regex
  const reRepeatedReservedCharacters = /([<>:"/\\|?*\u0000-\u001F]){2,}/g; // eslint-disable-line no-control-regex

  if (typeof string !== 'string') {
    throw new TypeError('Expected a string');
  }

  const replacement = options.replacement === undefined ? '!' : options.replacement;

  if (filenameReservedRegex().test(replacement) && reControlChars.test(replacement)) {
    throw new Error('Replacement string cannot contain reserved filename characters');
  }

  /* eslint-disable no-param-reassign */
  if (replacement.length > 0) {
    string = string.replace(reRepeatedReservedCharacters, '$1');
  }

  string = string.normalize('NFD');
  string = string.replace(reRelativePath, replacement);
  string = string.replace(filenameReservedRegex(), replacement);
  string = string.replace(reControlChars, replacement);
  string = string.replace(reTrailingPeriods, '');

  if (replacement.length > 0) {
    const startedWithDot = string[0] === '.';

    // We removed the whole filename
    if (!startedWithDot && string[0] === '.') {
      string = replacement + string;
    }

    // We removed the whole extension
    if (string[string.length - 1] === '.') {
      string += replacement;
    }
  }

  string = windowsReservedNameRegex().test(string) ? string + replacement : string;
  const allowedLength =
    typeof options.maxLength === 'number' ? options.maxLength : MAX_FILENAME_LENGTH;
  if (string.length > allowedLength) {
    const extensionIndex = string.lastIndexOf('.');
    if (extensionIndex === -1) {
      string = string.slice(0, allowedLength);
    } else {
      const filename = string.slice(0, extensionIndex);
      const extension = string.slice(extensionIndex);
      string = filename.slice(0, Math.max(1, allowedLength - extension.length)) + extension;
    }
  }
  /* eslint-enable no-param-reassign */

  return string;
}

module.exports = filenamify;
