"use strict";

const js = require("@eslint/js");
const { defineConfig, globalIgnores } = require("eslint/config");
const n = require("eslint-plugin-n");
const globals = require("globals");
const { default: markdown } = require("@eslint/markdown");

const messages = {
  gh237: "See https://github.com/mochajs/mocha/issues/237",
  gh3604: "See https://github.com/mochajs/mocha/issues/3604",
};

module.exports = defineConfig(
  {
    files: ["**/*.{cjs,js,mjs}"],
    extends: [n.configs["flat/recommended-script"], js.configs.recommended],
    languageOptions: {
      ecmaVersion: 2022,
      globals: {
        ...globals.browser,
        ...globals.node,
      },
    },
    rules: {
      "no-redeclare": "off",
      "no-undef": "off",
      "n/no-process-exit": "off",
      "n/no-unpublished-require": "off",
      "n/no-unsupported-features/node-builtins": "off",
      strict: ["error", "global"],
    },
    settings: {
      "import/extensions": [".cjs", ".js", ".mjs"],
      "import/resolver": {
        node: {
          extensions: [".cjs", ".js", ".mjs"],
        },
      },
      node: {
        tryExtensions: [".cjs", ".js", ".json", ".node", ".mjs"],
      },
    },
  },
  {
    files: [
      ".wallaby.cjs",
      "package-scripts.js",
      "bin/*",
      "lib/cli/**/*.js",
      "lib/nodejs/**/*.js",
      "scripts/**/*.{js,cjs}",
      "test/**/*.{js,mjs}",
    ],
    languageOptions: {
      globals: globals.node,
    },
  },
  {
    files: ["**/*.js", "**/*.mjs", "lib/nodejs/esm-utils.cjs"],
    languageOptions: {
      sourceType: "module",
      ecmaVersion: 2025,
    },
  },
  {
    files: ["test/**/*.{js,mjs,cjs}"],
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.mocha,
        ...globals.node,
        expect: "readonly",
      },
    },
  },
  {
    files: ["bin/*", "lib/**/*.{js,cjs}"],
    ignores: ["lib/stats-collector.js"],
    rules: {
      "no-restricted-globals": [
        "error",
        {
          message: messages.gh237,
          name: "setTimeout",
        },
        {
          message: messages.gh237,
          name: "clearTimeout",
        },
        {
          message: messages.gh237,
          name: "setInterval",
        },
        {
          message: messages.gh237,
          name: "clearInterval",
        },
        {
          message: messages.gh237,
          name: "setImmediate",
        },
        {
          message: messages.gh237,
          name: "clearImmediate",
        },
        {
          message: messages.gh237,
          name: "Date",
        },
      ],
      "no-restricted-modules": ["error", "timers"],
      "no-restricted-syntax": [
        "error",
        // disallow `global.setTimeout()`, `global.setInterval()`, etc.
        {
          message: messages.gh237,
          selector:
            "CallExpression[callee.object.name=global][callee.property.name=/(set|clear)(Timeout|Immediate|Interval)/]",
        },
        // disallow `new global.Date()`
        {
          message: messages.gh237,
          selector:
            "NewExpression[callee.object.name=global][callee.property.name=Date]",
        },
        // disallow property access of `global.<timer>.*`
        {
          message: messages.gh237,
          selector:
            "*[object.object.name=global][object.property.name=/(Date|(set|clear)(Timeout|Immediate|Interval))/]:expression",
        },
      ],
    },
  },
  {
    files: ["lib/reporters/*.{js,cjs}"],
    rules: {
      "no-restricted-syntax": [
        "error",
        // disallow Reporters using `console.log()`
        {
          message: messages.gh3604,
          selector:
            "CallExpression[callee.object.name=console][callee.property.name=log]",
        },
      ],
    },
  },
  {
    files: ["**/*.md"],
    plugins: {
      markdown,
    },
    extends: ["markdown/recommended"],
    language: "markdown/gfm",
    rules: {
      "markdown/no-multiple-h1": "off",
      "markdown/fenced-code-language": "off",
      "markdown/no-missing-label-refs": "off",
      "markdown/no-duplicate-headings": ["error", { checkSiblingsOnly: true }],
    },
  },
  globalIgnores([
    "**/*.{fixture,min}.{js,mjs,cjs}",
    "coverage/**",
    "docs/{.astro,dist}/**",
    "mocha.js",
    "out/**",
    "test/browser/.generated/**",
    "test/integration/fixtures/**",
    "scripts/pick-from-package-json.js",
  ]),
);
