text: "use strict";
  
  const _ = require("lodash");
  const chalk = require("chalk");
  const path = require("path");
  const stringWidth = require("string-width");
  const symbols = require("log-symbols");
  const utils = require("postcss-reporter/lib/util");
  let table;
  
  const MARGIN_WIDTHS = 9;
  
  const levelColors = {
    info: "blue",
    warning: "yellow",
    error: "red"
  };
  
  function deprecationsFormatter(results) {
    const allDeprecationWarnings = _.flatMap(results, "deprecations");
    const uniqueDeprecationWarnings = _.uniqBy(allDeprecationWarnings, "text");
  
    if (!uniqueDeprecationWarnings || !uniqueDeprecationWarnings.length) {
      return "";
    }
  
    return uniqueDeprecationWarnings.reduce((output, warning) => {
      output += chalk.yellow("Deprecation Warning: ");
      output += warning.text;
  
      if (warning.reference) {
        output += chalk.dim(" See: ");
        output += chalk.dim.underline(warning.reference);
      }
  
      return output + "\n";
    }, "\n");
  }
  
  function invalidOptionsFormatter(results) {
    const allInvalidOptionWarnings = _.flatMap(results, r =>
      r.invalidOptionWarnings.map(w => w.text)
    );
    const uniqueInvalidOptionWarnings = _.uniq(allInvalidOptionWarnings);
  
    return uniqueInvalidOptionWarnings.reduce((output, warning) => {
      output += chalk.red("Invalid Option: ");
      output += warning;
  
      return output + "\n";
    }, "\n");
  }
  
  function logFrom(fromValue) {
    if (fromValue.charAt(0) === "<") return fromValue;
  
    return path
      .relative(process.cwd(), fromValue)
      .split(path.sep)
      .join("/");
  }
  
  function getMessageWidth(columnWidths) {
    if (!process.stdout.isTTY) {
      return columnWidths[3];
    }
  
    const availableWidth =
      process.stdout.columns < 80 ? 80 : process.stdout.columns;
    const fullWidth = _.sum(_.values(columnWidths));
  
    // If there is no reason to wrap the text, we won't align the last column to the right
    if (availableWidth > fullWidth + MARGIN_WIDTHS) {
      return columnWidths[3];
    }
  
    return availableWidth - (fullWidth - columnWidths[3] + MARGIN_WIDTHS);
  }
  
  function formatter(messages, source) {
    if (!messages.length) return "";
  
    const orderedMessages = _.sortBy(
      messages,
      m => (m.line ? 2 : 1), // positionless first
      m => m.line,
      m => m.column
    );
  
    // Create a list of column widths, needed to calculate
    // the size of the message column and if needed wrap it.
    const columnWidths = { 0: 1, 1: 1, 2: 1, 3: 1, 4: 1 };
  
    const calculateWidths = function(columns) {
      _.forOwn(columns, (value, key) => {
        const normalisedValue = value ? value.toString() : value;
  
        columnWidths[key] = Math.max(
          columnWidths[key],
          stringWidth(normalisedValue)
        );
      });
  
      return columns;
    };
  
    let output = "\n";
  
    if (source) {
      output += chalk.underline(logFrom(source)) + "\n";
    }
  
    const cleanedMessages = orderedMessages.map(message => {
      const location = utils.getLocation(message);
      const severity = message.severity;
      const row = [
        location.line || "",
        location.column || "",
        symbols[severity]
          ? chalk[levelColors[severity]](symbols[severity])
          : severity,
        message.text
          // Remove all control characters (newline, tab and etc)
          .replace(/[\x01-\x1A]+/g, " ") // eslint-disable-line no-control-regex
          .replace(/\.$/, "")
          .replace(
            new RegExp(_.escapeRegExp("(" + message.rule + ")") + "$"),
            ""
          ),
        chalk.dim(message.rule || "")
      ];
  
      calculateWidths(row);
  
      return row;
    });
  
    if (!table) {
      table = require("table");
    }
  
    output += table
      .table(cleanedMessages, {
        border: table.getBorderCharacters("void"),
        columns: {
          0: { alignment: "right", width: columnWidths[0], paddingRight: 0 },
          1: { alignment: "left", width: columnWidths[1] },
          2: { alignment: "center", width: columnWidths[2] },
          3: {
            alignment: "left",
            width: getMessageWidth(columnWidths),
            wrapWord: getMessageWidth(columnWidths) > 1
          },
          4: { alignment: "left", width: columnWidths[4], paddingRight: 0 }
        },
        drawHorizontalLine: () => false
      })
      .split("\n")
      .map(el =>
        el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(p1 + ":" + p2))
      )
      .join("\n");
  
    return output;
  }
  
  module.exports = function(results) {
    let output = invalidOptionsFormatter(results);
  
    output += deprecationsFormatter(results);
  
    output = results.reduce((output, result) => {
      // Treat parseErrors as warnings
      if (result.parseErrors) {
        result.parseErrors.forEach(error =>
          result.warnings.push({
            line: error.line,
            column: error.column,
            rule: error.stylelintType,
            severity: "error",
            text: `${error.text} (${error.stylelintType})`
          })
        );
      }
  
      output += formatter(result.warnings, result.source);
  
      return output;
    }, output);
  
    // Ensure consistent padding
    output = output.trim();
  
    if (output !== "") {
      output = "\n" + output + "\n\n";
    }
  
    return output;
  };
  