/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint-env node */

import stylelint from "stylelint";
import valueParser from "postcss-value-parser";
import { namespace, isUrlFunction, isWord } from "../helpers.mjs";

const {
  utils: { report, ruleMessages, validateOptions },
} = stylelint;

const ruleName = namespace("no-browser-refs-in-toolkit");

const messages = ruleMessages(ruleName, {
  rejected: url =>
    `${url} is part of Desktop Firefox and cannot be used by this code (which has to also work elsewhere).`,
});

const meta = {
  url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/stylelint-plugin-mozilla/rules/no-browser-refs-in-toolkit.html",
  fixable: false,
};

function extractUrlFromNode(node) {
  if (!node) {
    return null;
  }

  if (node.type === "string") {
    return node.value;
  }

  if (isUrlFunction(node)) {
    const urlContent = node.nodes[0];
    if (urlContent && (urlContent.type === "string" || isWord(urlContent))) {
      return urlContent.value;
    }
  }

  return null;
}

function isBrowserUrl(url) {
  return (
    url.startsWith("chrome://browser") ||
    url.startsWith("resource:///") ||
    url.startsWith("resource://app/") ||
    /moz-src:\/\/\w*\/browser\//.test(url)
  );
}

const ruleFunction = primaryOption => {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, {
      actual: primaryOption,
      possible: [true],
    });

    if (!validOptions) {
      return;
    }

    root.walkAtRules("import", atRule => {
      const params = valueParser(atRule.params);
      const firstParam = params.nodes[0];
      const importUrl = extractUrlFromNode(firstParam);

      if (importUrl && isBrowserUrl(importUrl)) {
        report({
          message: messages.rejected(importUrl),
          node: atRule,
          result,
          ruleName,
        });
      }
    });

    root.walkDecls(decl => {
      const parsed = valueParser(decl.value);

      parsed.nodes.forEach(node => {
        const url = extractUrlFromNode(node);

        if (url && isBrowserUrl(url)) {
          report({
            message: messages.rejected(url),
            node: decl,
            result,
            ruleName,
          });
        }
      });
    });
  };
};

ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = meta;

export default ruleFunction;
