const { rules: baseStyleRules } = require('eslint-config-airbnb-base/rules/style');
const tsconfigJson = require('./tsconfig.json');
require('@rushstack/eslint-patch/modern-module-resolution');

module.exports = {
  root: true,
  env: {
    node: true,
    es2022: true, // add globals and sets parserOptions.ecmaVersion to 2022
  },
  extends: [
    // Vue specific base rules, `eslint-plugin-vue`
    'plugin:vue/vue3-recommended',

    // Extends `eslint-config-airbnb`
    '@vue/eslint-config-airbnb-with-typescript',

    // - Sets base parser and plugin options.
    // - Includes `plugin:@typescript-eslint/recommended`. But incompatible with
    //   `strict-type-checked` and `stylistic-type-checked`, see https://github.com/vuejs/eslint-config-typescript/issues/67.
    '@vue/typescript/recommended',
  ],
  rules: {
    ...getOwnRules(),
    ...getTurnedOffBrokenRules(),
    ...getOpinionatedRuleOverrides(),
    ...getTodoRules(),
  },
};

function getOwnRules() {
  return {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'linebreak-style': ['error', 'unix'], // This is also enforced in .editorconfig and .gitattributes files
    'import/order': [ // Enforce strict import order taking account into aliases
      'error',
      {
        groups: [ // Enforce more strict order than AirBnb
          'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
        pathGroups: [ // Fix manually configured paths being incorrectly grouped as "external"
          ...getAliasesFromTsConfig(),
          'js-yaml-loader!@/**',
        ].map((pattern) => ({ pattern, group: 'internal' })),
      },
    ],
  };
}

function getTodoRules() { // Should be worked on separate future commits
  return {
    'import/no-extraneous-dependencies': 'off',
    // Accessibility improvements:
    'vuejs-accessibility/form-control-has-label': 'off',
    'vuejs-accessibility/click-events-have-key-events': 'off',
    'vuejs-accessibility/anchor-has-content': 'off',
    'vuejs-accessibility/accessible-emoji': 'off',
  };
}

function getTurnedOffBrokenRules() {
  return {
    // Broken in TypeScript
    'no-useless-constructor': 'off', // Cannot interpret TypeScript constructors
    'no-shadow': 'off', // Fails with TypeScript enums
  };
}

function getOpinionatedRuleOverrides() {
  return {
    // https://erkinekici.com/articles/linting-trap#no-use-before-define
    'no-use-before-define': 'off',
    '@typescript-eslint/no-use-before-define': 'off',
    // https://erkinekici.com/articles/linting-trap#arrow-body-style
    'arrow-body-style': 'off',
    // https://erkinekici.com/articles/linting-trap#no-plusplus
    'no-plusplus': 'off',
    // https://erkinekici.com/articles/linting-trap#no-param-reassign
    'no-param-reassign': 'off',
    // https://erkinekici.com/articles/linting-trap#class-methods-use-this
    'class-methods-use-this': 'off',
    // https://erkinekici.com/articles/linting-trap#importprefer-default-export
    'import/prefer-default-export': 'off',
    // https://erkinekici.com/articles/linting-trap#disallowing-for-of
    // Original: https://github.com/airbnb/javascript/blob/d8cb404da74c302506f91e5928f30cc75109e74d/packages/eslint-config-airbnb-base/rules/style.js#L333-L351
    'no-restricted-syntax': [
      baseStyleRules['no-restricted-syntax'][0],
      ...baseStyleRules['no-restricted-syntax'].slice(1).filter((rule) => rule.selector !== 'ForOfStatement'),
    ],
  };
}

function getAliasesFromTsConfig() {
  return Object.keys(tsconfigJson.compilerOptions.paths)
    .map((path) => `${path}*`);
}
