// @ts-check

"use strict";

const {
  addError
} = require("markdownlint-rule-helpers");

const { indentFor } = require("./helper");

const isAfterIgnoredWord = (ignoredWords, line, i) => {
  for (const ignoredWord of ignoredWords) {
    const lastWordInLine = line.substring(i - ignoredWord.length, i);
    if (ignoredWord === lastWordInLine.toLowerCase()) {
      return true;
    }
  }

  return false;
};

module.exports = {
  "names": [ "max-one-sentence-per-line" ],
  "description": "Max 1 sentence should be on a line",
  "information": new URL(
    "https://github.com/aepfli/markdownlint-rule-max-one-sentence-per-line"
  ),
  "tags": [ "sentences" ],
  "function": (params, onError) => {

    const ignoredWords = params.config.ignored_words ||
      [ "ie", "i.e", "eg", "e.g", "etc", "ex" ];
    const lineEndings = params.config.line_endings || [ ".", "?", "!" ];
    const sentenceStartRegex = params.config.sentence_start ||
      "^\\s+(\\w|[*_'\"])";
    const contextSize = Number(params.config.context_length || 14);
    const indentation = params.config.indentation || "  ";

    const sentenceStart = new RegExp(sentenceStartRegex);

    const relevantTokens = [];
    for (let i = 0; i < params.tokens.length; i++) {
      const token = params.tokens[i];
      if (token.type === "paragraph_open" &&
        params.tokens[i + 1].type === "inline") {
        relevantTokens.push(params.tokens[i + 1]);
      }
    }

    for (const relevantToken of relevantTokens) {

      for (const token of relevantToken.children) {
        const lineNumber = token.lineNumber;
        if (token.type === "text") {
          const content = token.content;
          for (let i = 0; i < content.length - 2; i += 1) {

            if (lineEndings.includes(content[i])) {
              const sentence = sentenceStart.exec(content.substr(i + 1));
              if (
                sentence !== null &&
                !isAfterIgnoredWord(ignoredWords, content, i)
              ) {
                const spaces = sentence[1];
                const pointInLine = token.line.indexOf(content) + i;
                addError(
                  onError,
                  lineNumber,
                  null,
                  // eslint-disable-next-line max-len
                  content.substr(Math.max(0, i - (contextSize / 2)), contextSize),
                  [ pointInLine, spaces.length ],
                  {
                    "lineNumber": lineNumber,
                    "editColumn": pointInLine + 2,
                    "deleteCount": spaces.length,
                    // eslint-disable-next-line max-len
                    "insertText": "\n" + indentFor(relevantToken.line, indentation)
                  }
                );
              }
            }
          }
        }
      }
    }
  }
};
