// @ts-check

import eslint from '@eslint/js'
import reactConfigs from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import globals from 'globals'

import simpleImportSort from 'eslint-plugin-simple-import-sort'
import tseslint from 'typescript-eslint'

// @ts-ignore
const reactConfig = reactConfigs.configs.flat.recommended

// tseslint.config() is a helper function that simply provides type safety for the ESLint flat config object.
// Instead of an array of config objects, pass each object as an argument to tseslint.config()
export default tseslint.config(
  {
    // Global ignore patterns
    ignores: [
      '**/dist/**/*',
      '**/node_modules/**/*',
      '**/tests/**/*',
      'generators/**/template/**/*',
      '**/coverage/**/*',
      '**/dist/**/*',
      '**/jest.config.ts',
      '**/prettier.config.js',
      'eslint.config.mjs',
      '**/next.config.js',
      '**/.next/**/*',
      '**/test-results/*',
      '**/playwright-report/*',
      '**/playwright-report*',
      '**/*.js',
      // Ignore stories for now
      '**/*.stories.tsx',
    ],
  },

  // Default ESLint rules
  eslint.configs.recommended,

  // Recommended TypeScript rules
  // TODO: Change to .strictTypeChecked
  ...tseslint.configs.strict,
  ...tseslint.configs.stylistic,

  // Additional global settings
  {
    ignores: ['**/*.js'],

    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
    plugins: {
      'simple-import-sort': simpleImportSort,
    },
    // Custom Rule Overrides and Settings
    rules: {
      // If we use "any", we typically do this on purpose
      '@typescript-eslint/no-explicit-any': 'off',

      // NestJS often defined empty classes but with decorators
      '@typescript-eslint/no-extraneous-class': 'off',

      // Ensure that promises are awaited
      '@typescript-eslint/no-floating-promises': 'error',
      '@typescript-eslint/require-await': 'error',

      // We prefer `type` over `interface` for type definitions
      '@typescript-eslint/consistent-type-definitions': ['error', 'type'],

      // This rule is too strict and we use `!` to indicate that a value cannot be null
      '@typescript-eslint/no-non-null-assertion': 'off',

      // We want unused vars to be an error. However, vars named `_` are often used to indicate that a value is unused and are allowed.
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': [
        'error',
        {
          args: 'all',
          argsIgnorePattern: '^_',
          caughtErrors: 'all',
          caughtErrorsIgnorePattern: '^_',
          destructuredArrayIgnorePattern: '^_',
          varsIgnorePattern: '^_',
          ignoreRestSiblings: true,
        },
      ],

      // This enforces that all template expressions are either number of string, other types must be stringified
      '@typescript-eslint/restrict-template-expressions': [
        'error',
        {
          allowNumber: true,
          allowBoolean: true,
        },
      ],

      // The "curly" rule ensures that all if, else if, else, for, while, or do blocks are followed by a block in braces, even if it is only a single line.
      // This will flag `if(condition) return x` and expect it to be written as `if (condition) { return x }`
      curly: ['error', 'all'],
      'no-inner-declarations': 'off',

      'padded-blocks': [
        'error',
        'never',
        {
          allowSingleLineBlocks: false,
        },
      ],

      'simple-import-sort/imports': [
        'error',
        {
          groups: [
            // Node.js builtins. You could also generate this regex if you use a `.js` config
            //  (e.g. `^(${require("module").builtinModules.join("|")})(/|$)`)
            [
              '^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)',
            ],

            // Side effect imports.
            ['^\\u0000'],

            // Any packages that starts with an @ but not libraries we defined in tsconfig.json:
            ['^@(?!(postxl|assets|backend|hooks|components|i18n|lib|layout|theme|ui|public))'],

            // Any other package.
            ['^'],

            // Internal PXL packages.
            ['^(@postxl|@assets|@backend|@hooks|@components|@i18n|@lib|@layout|@theme|@ui|@public)(/.*|$)'],

            // Parent imports. Put `..` last.
            ['^\\.\\.(?!/?$)', '^\\.\\./?$'],

            // Other relative imports. Put same-folder imports and `.` last.
            ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
          ],
        },
      ],
    },
  },

  // React-specific rules
  // Source: https://www.npmjs.com/package/eslint-plugin-react
  //
  // Currently, eslint-config-next only support eslint v8.x.
  // Until it is upgraded (and we upgraded to NextJS v15), we use the default
  // react and react-hooks eslint plugins.
  //
  // @ts-ignore
  {
    settings: {
      react: {
        version: '18.3',
      },
    },
    files: ['**/web/**/*.{ts,tsx,mtsx}', '**/frontend/**/*.{ts,tsx,mtsx}'],
    ...reactConfig,
    languageOptions: {
      ...reactConfig.languageOptions,
      globals: {
        ...globals.serviceworker,
        ...globals.browser,
      },
    },
    rules: {
      ...reactConfig.rules,
      'react/prop-types': 'off',
      'react/react-in-jsx-scope': 'off',
    },
  },
  {
    plugins: {
      'react-hooks': reactHooks,
    },
    files: ['**/web/**/*.{ts,tsx,mtsx}', '**/frontend/**/*.{ts,tsx,mtsx}'],
    rules: {
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'error',
    },
  },

  // Do not type check VFS files
  {
    files: ['**/vfs/**/*.ts', '**/vfs/**/*.tsx'],
    extends: [tseslint.configs.disableTypeChecked],
  },
)
