// @ts-check
const tseslint = require('typescript-eslint');
const angular = require('angular-eslint');
const prettierRecommended = require('eslint-plugin-prettier/recommended');
const preferArrow = require('eslint-plugin-prefer-arrow');
const localRules = require('eslint-plugin-local-rules');

module.exports = tseslint.config(
  // Global ignores
  {
    ignores: [
      'app-builds/**/*',
      'dist/**',
      'node_modules/**/*',
      'src/app/t.const.ts',
      'src/assets/bundled-plugins/**/*',
      'src/app/config/env.generated.ts',
      '.tmp/**/*',
      'packages/plugin-api/**/*',
      'packages/plugin-dev/**/*',
      'packages/shared-schema/**/*',
      'packages/super-sync-server/**/*',
      'packages/vite-plugin/**/*',
      'packages/*/dist/**/*',
    ],
  },
  // TypeScript files
  {
    files: ['**/*.ts'],
    extends: [
      ...tseslint.configs.recommended,
      ...angular.configs.tsRecommended,
      prettierRecommended,
    ],
    processor: angular.processInlineTemplates,
    plugins: {
      'prefer-arrow': preferArrow,
    },
    languageOptions: {
      parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
      },
    },
    rules: {
      // Disabled rules
      '@typescript-eslint/no-explicit-any': 'off',
      '@typescript-eslint/ban-ts-comment': 'off',
      '@typescript-eslint/no-empty-function': 'off',
      '@typescript-eslint/explicit-module-boundary-types': 'off',
      '@angular-eslint/component-selector': 'off',
      '@angular-eslint/no-input-rename': 'off',
      '@typescript-eslint/no-inferrable-types': 'off',
      'no-underscore-dangle': 'off',
      'arrow-body-style': 'off',
      '@typescript-eslint/member-ordering': 'off',
      'import/order': 'off',
      'arrow-parens': 'off',
      '@typescript-eslint/explicit-member-accessibility': 'off',

      // Enabled rules
      'prettier/prettier': 'error',
      '@typescript-eslint/no-unused-vars': [
        'error',
        { args: 'none', caughtErrors: 'none' },
      ],
      '@typescript-eslint/explicit-function-return-type': [
        'error',
        {
          allowExpressions: true,
          allowTypedFunctionExpressions: true,
          allowHigherOrderFunctions: true,
          allowDirectConstAssertionInArrowFunctions: true,
          allowConciseArrowFunctionExpressionsStartingWithVoid: true,
        },
      ],
      '@typescript-eslint/naming-convention': [
        'error',
        {
          selector: 'default',
          format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
          leadingUnderscore: 'allowSingleOrDouble',
          trailingUnderscore: 'allow',
          filter: { regex: '(should)|@tags', match: false },
        },
        {
          selector: 'variable',
          format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
          leadingUnderscore: 'allowSingleOrDouble',
          trailingUnderscore: 'allow',
        },
        { selector: 'enum', format: ['PascalCase', 'UPPER_CASE'] },
        { selector: 'typeLike', format: ['PascalCase'] },
      ],
      'prefer-const': 'error',
      '@typescript-eslint/no-unused-expressions': 'error',
      '@typescript-eslint/no-empty-object-type': 'error',
      'max-len': [
        'error',
        {
          ignorePattern: '^import \\{.+;$',
          ignoreRegExpLiterals: true,
          ignoreStrings: true,
          ignoreUrls: true,
          code: 150,
        },
      ],
      'id-blacklist': 'error',
      // @typescript-eslint/member-delimiter-style removed in v8 - Prettier handles this
      'no-shadow': 'off',
      '@typescript-eslint/no-shadow': 'error',
      'comma-dangle': ['error', 'always-multiline'],
      'no-mixed-operators': 'error',
      'prefer-arrow/prefer-arrow-functions': 'error',
      '@angular-eslint/directive-selector': [
        'error',
        { type: 'attribute', prefix: '', style: 'camelCase' },
      ],
      // @typescript-eslint/ban-types replaced by specific rules in v8
      '@typescript-eslint/no-unsafe-function-type': 'error',
      '@typescript-eslint/no-wrapper-object-types': 'error',
    },
  },
  {
    files: ['packages/sync-core/**/*.ts'],
    rules: {
      'no-restricted-imports': [
        'error',
        {
          paths: [
            {
              name: '@sp/shared-schema',
              message:
                '@sp/sync-core must stay domain-agnostic; shared-schema is SP-specific.',
            },
          ],
          patterns: [
            {
              group: [
                '@angular/*',
                '@ngrx/*',
                '@sp/shared-schema/*',
                '../shared-schema/*',
                '../shared-schema/**',
                '../../shared-schema/*',
                '../../shared-schema/**',
                '**/shared-schema/*',
                '**/shared-schema/**',
                'src/app/*',
                'src/app/**',
                '**/src/app/*',
                '**/src/app/**',
              ],
              message:
                '@sp/sync-core must not import Angular, NgRx, app code, or SP-specific schema packages.',
            },
          ],
        },
      ],
      'no-restricted-syntax': [
        'error',
        {
          selector: 'ImportExpression',
          message:
            '@sp/sync-core must not use dynamic imports; they bypass package-boundary checks.',
        },
      ],
    },
  },
  {
    files: ['packages/sync-providers/**/*.ts'],
    rules: {
      'no-restricted-imports': [
        'error',
        {
          paths: [
            {
              name: '@sp/shared-schema',
              message: '@sp/sync-providers must not import SP-specific schema packages.',
            },
          ],
          patterns: [
            {
              group: [
                '@angular/*',
                '@ngrx/*',
                '@sp/shared-schema/*',
                '@sp/sync-core/*',
                '**/shared-schema/*',
                '**/shared-schema/**',
                '**/sync-core/*',
                '**/sync-core/**',
                'src/app/*',
                'src/app/**',
                '**/src/app/*',
                '**/src/app/**',
              ],
              message:
                '@sp/sync-providers must use only public @sp/sync-core exports and must not import Angular, NgRx, app code, or SP-specific schema packages.',
            },
          ],
        },
      ],
      'no-restricted-syntax': [
        'error',
        {
          selector: 'ImportExpression',
          message:
            '@sp/sync-providers must not use dynamic imports; they bypass package-boundary checks.',
        },
      ],
    },
  },
  // NgRx effects files - require hydration guards on selector-based effects
  {
    files: ['**/*.effects.ts'],
    plugins: {
      'local-rules': localRules,
    },
    rules: {
      'local-rules/require-hydration-guard': 'error',
      'local-rules/require-entity-registry': 'warn',
      'local-rules/no-actions-in-effects': 'error',
      'local-rules/no-multi-entity-effect': 'warn',
    },
  },
  // Op-log persistence: inside an adapter.transaction() callback only the tx
  // handle may be used — adapter methods enqueue behind the transaction's own
  // FIFO queue slot on the SQLite backend and deadlock (see
  // SqliteOpLogAdapter._serialize()).
  {
    files: ['src/app/op-log/**/*.ts'],
    plugins: {
      'local-rules': localRules,
    },
    rules: {
      'local-rules/no-adapter-in-tx': 'error',
    },
  },
  // App code must route logging through Log/SyncLog/OpLog/... helpers.
  // Direct console.* calls bypass the exportable log history users attach
  // to bug reports. The Log implementation itself, tests, and benchmarks
  // (which intentionally dump timing numbers to stdout) are exempt.
  {
    files: ['src/app/**/*.ts'],
    ignores: ['src/app/**/*.spec.ts', 'src/app/**/*.benchmark.ts', 'src/app/core/log.ts'],
    rules: {
      'no-console': 'error',
    },
  },
  // HTML files
  {
    files: ['**/*.html'],
    extends: [...angular.configs.templateRecommended, prettierRecommended],
    rules: {
      '@angular-eslint/template/no-negated-async': 'off',
      'prettier/prettier': 'error',
    },
  },
);
