import eslint from "@eslint/js";
import jsdoc from "eslint-plugin-jsdoc";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";
import tseslint from "typescript-eslint";

const jsDocConfig = jsdoc.configs["flat/recommended-typescript-error"];

export default tseslint.config(
	eslint.configs.recommended,
	...tseslint.configs.strictTypeChecked,
	{
		name: "eslint/global-ignores",
		// globally ignore below directories and files
		ignores: [
			"**/build",
			"**/docs/**/*",
			"**/node_modules",
			"**/examples",
			// vitest config files are runtime build configs, intentionally
			// outside the TS project graph — `@typescript-eslint`'s type-aware
			// rules can't resolve them and report "not found by the project
			// service" parsing errors. Vitest does its own config validation.
			"**/vitest.config.ts",
		],
	},
	{
		name: "eslint/global-rules",
		languageOptions: {
			ecmaVersion: 2022,
			sourceType: "module",
			globals: {
				...globals.browser,
			},
		},
		files: ["**/src/**/*.js", "**/tests/**/*.js"],
		plugins: {
			jsdoc,
		},
		rules: {
			// http://eslint.org/docs/rules/
			"accessor-pairs": "error",
			"array-callback-return": "error",
			"arrow-body-style": ["error", "always"],
			"block-scoped-var": "error",
			camelcase: ["off", { properties: "never" }],
			"constructor-super": "error",
			curly: ["error", "all"],
			eqeqeq: ["error", "allow-null"],
			"func-call-spacing": ["error", "never"],
			"for-direction": "error",
			"handle-callback-err": ["error", "^(err|error)$"],
			"key-spacing": ["off", { beforeColon: false, afterColon: true }],
			"keyword-spacing": ["error", { before: true, after: true }],
			"new-cap": ["error", { newIsCap: true, capIsNew: false }],
			"new-parens": "error",
			"no-array-constructor": "error",
			"no-caller": "error",
			"no-class-assign": "error",
			"no-case-declarations": "error",
			"no-constructor-return": "error",
			"no-duplicate-imports": "error",
			"no-dupe-class-members": "error",
			"no-eval": "error",
			"no-extend-native": "error",
			"no-extra-bind": "error",
			"no-extra-parens": ["error", "functions"],
			"no-floating-decimal": "error",
			"no-implied-eval": "error",
			"no-implicit-coercion": "off",
			"no-implicit-globals": "error",
			"no-import-assign": "error",
			"no-iterator": "error",
			"no-label-var": "error",
			"no-labels": ["error", { allowLoop: false, allowSwitch: false }],
			"no-lone-blocks": "error",
			"no-loss-of-precision": "error",
			"no-multi-str": "error",
			"no-native-reassign": "error",
			"no-negated-in-lhs": "error",
			"no-new": "error",
			"no-new-func": "error",
			"no-object-constructor": "error",
			"no-new-native-nonconstructor": "error",
			"no-new-require": "error",
			"no-new-wrappers": "error",
			"no-octal-escape": "error",
			"no-path-concat": "error",
			"no-proto": "error",
			"no-prototype-builtins": "off",
			"no-promise-executor-return": "error",
			"no-return-assign": ["error", "except-parens"],
			"no-self-compare": "error",
			"no-sequences": "off",
			"no-template-curly-in-string": "off",
			"no-this-before-super": "error",
			"no-throw-literal": "off",
			"no-trailing-spaces": "error",
			"no-undef": "error",
			"no-undef-init": "error",
			"no-unmodified-loop-condition": "error",
			"no-unneeded-ternary": ["off", { defaultAssignment: false }],
			"no-unreachable": "error",
			"no-unused-vars": [
				"error",
				{ args: "after-used", argsIgnorePattern: "^_" },
			],
			"@typescript-eslint/no-unused-vars": [
				"error",
				{ args: "after-used", argsIgnorePattern: "^_" },
			],
			"no-unused-private-class-members": "error",
			"no-useless-call": "off",
			"no-useless-computed-key": "error",
			"no-useless-constructor": "error",
			// used in RegExp
			"no-useless-escape": "off",
			"no-useless-rename": "error",
			"no-whitespace-before-property": "error",
			"object-property-newline": [
				"error",
				{ allowMultiplePropertiesPerLine: true },
			],
			"one-var": ["off", { initialized: "never" }],
			"operator-linebreak": [
				"off",
				"after",
				{ overrides: { "?": "before", ":": "before" } },
			],
			"padded-blocks": ["off", "never"],
			"prefer-arrow-callback": "error",
			quotes: [
				"error",
				"double",
				{ avoidEscape: true, allowTemplateLiterals: true },
			],
			"rest-spread-spacing": ["error", "never"],
			"semi-spacing": ["error", { before: false, after: true }],
			"space-before-blocks": ["error", "always"],
			"space-before-function-paren": ["off", "always"],
			"space-infix-ops": "error",
			"space-unary-ops": ["off", { words: true, nonwords: false }],
			"spaced-comment": [
				"off",
				"always",
				{
					line: { markers: ["*package", "!", ","] },
					block: {
						balanced: true,
						markers: ["*package", "!", ","],
						exceptions: ["*"],
					},
				},
			],
			"template-curly-spacing": ["error", "never"],
			"unicode-bom": ["error", "never"],
			"valid-typeof": ["error", { requireStringLiterals: true }],
			"yield-star-spacing": ["error", "both"],
			yoda: ["error", "never"],
			"jsdoc/require-hyphen-before-param-description": "error",
			"jsdoc/no-undefined-types": "off",
			"@typescript-eslint/no-dynamic-delete": "off",
			"@typescript-eslint/no-extraneous-class": "off",
		},
	},
	{
		files: ["**/*.js", "**/*.mjs"],
		...tseslint.configs.disableTypeChecked,
	},
	{
		...jsDocConfig,
		files: ["**/*.{ts,tsx,mts,cts}"],
		plugins: {
			jsdoc,
			"react-refresh": reactRefresh,
		},
		rules: {
			"no-undef": "off",
			"no-unused-vars": "off",
			"@typescript-eslint/no-unused-vars": [
				"error",
				{ args: "after-used", argsIgnorePattern: "^_" },
			],
			"prefer-template": "error",
			"@typescript-eslint/no-explicit-any": "off",
			"@typescript-eslint/ban-ts-comment": "off",
			"@typescript-eslint/no-dynamic-delete": "off",
			"@typescript-eslint/no-unsafe-call": "off",
			"@typescript-eslint/no-unsafe-member-access": "off",
			"@typescript-eslint/no-unsafe-argument": "off",
			"@typescript-eslint/no-unsafe-assignment": "off",
			"@typescript-eslint/no-unnecessary-condition": "warn",
			"@typescript-eslint/no-invalid-void-type": "off",
			"@typescript-eslint/no-unsafe-return": "off",
			"@typescript-eslint/no-non-null-assertion": "warn",
			"@typescript-eslint/no-unnecessary-type-assertion": "error",
			"@typescript-eslint/no-empty-object-type": "warn",
			"@typescript-eslint/no-deprecated": "error",
			"@typescript-eslint/restrict-template-expressions": [
				"error",
				{ allowNumber: true },
			],
			...jsDocConfig.rules,
			"jsdoc/require-jsdoc": "off",
			"jsdoc/no-defaults": "off",
			"jsdoc/require-returns": "off",
			"react-refresh/only-export-components": "warn",
		},
		languageOptions: {
			parserOptions: {
				projectService: true,
				tsconfigRootDir: import.meta.dirname,
			},
		},
	},
	{
		// Test-file overrides. Tests legitimately assert preconditions
		// (`?.()!` on optional adapter methods the test knows exist),
		// use deprecated setup helpers like `video.init` (kept around
		// specifically to make test scaffolding terse), and may declare
		// async test bodies without an `await` yet. None of those
		// patterns warrant blocking the build.
		name: "eslint/tests",
		files: ["**/tests/**/*.{ts,tsx,mts,cts}"],
		rules: {
			"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
			"@typescript-eslint/no-deprecated": "off",
			"@typescript-eslint/require-await": "off",
			"@typescript-eslint/unbound-method": "off",
		},
	},
);
