import { fileURLToPath } from 'node:url';

import { includeIgnoreFile } from '@eslint/compat';
import js from '@eslint/js';
import prettier from 'eslint-config-prettier';
import preferLet from 'eslint-plugin-prefer-let';
import storybook from 'eslint-plugin-storybook';
import svelte from 'eslint-plugin-svelte';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import { defineConfig } from 'eslint/config';
import globals from 'globals';
import ts from 'typescript-eslint';

import svelteConfig from './svelte/svelte.config.js';

const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url));

export default defineConfig(
  eslintPluginUnicorn.configs.unopinionated,
  includeIgnoreFile(gitignorePath),
  // `crates/` (Rust workspace crates) is not in `.gitignore` but should not be
  // linted. `svelte/static/` contains vendored files like `mockServiceWorker.js`
  // (auto-generated by MSW) that should not be linted either.
  { ignores: ['crates/', 'svelte/static/'] },
  js.configs.recommended,
  ...ts.configs.recommended,
  ...svelte.configs.recommended,
  ...svelte.configs.prettier,
  ...storybook.configs['flat/recommended'],
  prettier,
  {
    plugins: {
      'prefer-let': preferLet,
    },

    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
        // Defined at build time by Vite (see `vite.config.ts`) and declared
        // ambiently in `src/app.d.ts`. ESLint's `no-undef` rule does not see
        // ambient `.d.ts` declarations, so we have to spell it out here.
        __TEST__: 'readonly',
      },

      parserOptions: {
        tsconfigRootDir: fileURLToPath(new URL('.', import.meta.url)),
      },
    },

    rules: {
      // it's fine to use `return` without a value and rely on the implicit `undefined` return value
      'getter-return': 'off',

      'prefer-const': 'off',
      'prefer-let/prefer-let': 'error',

      'unicorn/explicit-length-check': ['error', { 'non-zero': 'not-equal' }],
      // disabled because we don't want to go all-in on ES6 modules for Node.js code yet
      'unicorn/prefer-module': 'off',
      // disabled because it seems unnecessary
      'unicorn/prefer-number-properties': 'off',
      // disabled because of false positives on non-array `push()` methods
      'unicorn/prefer-single-call': 'off',
      // disabled because switch statements in JS are quite error-prone
      'unicorn/prefer-switch': 'off',
      // disabled because Svelte component `<script>` blocks instantiate
      // synchronously, so top-level await is not appropriate there
      'unicorn/prefer-top-level-await': 'off',
    },
  },
  {
    files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],

    languageOptions: {
      parserOptions: {
        projectService: true,
        extraFileExtensions: ['.svelte'],
        parser: ts.parser,
        svelteConfig,
        tsconfigRootDir: fileURLToPath(new URL('svelte', import.meta.url)),
      },
    },
  },
);
