import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import unusedImports from "eslint-plugin-unused-imports";
import tseslint from "typescript-eslint";
import { globalIgnores } from "eslint/config";

export default tseslint.config([
  globalIgnores(["dist", "release", "Mobile", "src/mcp-server/node_modules"]),
  {
    files: ["**/*.{ts,tsx}"],
    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      reactRefresh.configs.vite,
    ],
    plugins: {
      "react-hooks": reactHooks,
      "unused-imports": unusedImports,
    },
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    rules: {
      "unused-imports/no-unused-imports": "error",
      "unused-imports/no-unused-vars": [
        "warn",
        {
          vars: "all",
          varsIgnorePattern: "^_",
          args: "after-used",
          argsIgnorePattern: "^_",
        },
      ],
      "@typescript-eslint/no-unused-vars": "off",
      "@typescript-eslint/no-explicit-any": "warn",
      "@typescript-eslint/no-unused-expressions": "warn",
      "no-empty": "warn",
      "no-control-regex": "off",
      "no-useless-assignment": "off",
      "preserve-caught-error": "off",
      "react-hooks/exhaustive-deps": "warn",
      "react-hooks/rules-of-hooks": "error",
      "react-refresh/only-export-components": "warn",
    },
  },
  {
    // MySQL has no RETURNING clause, and drizzle's mysql-core does not expose
    // the method at all — a bare .returning() is a TypeError there, not a bad
    // query, and it only fails on the engine no test in this repo runs against.
    //
    // 175 call sites were migrated off it. This is what stops number 176.
    // Writes that need rows back go through repositories/returning.ts, which
    // picks one statement or a read-then-write transaction per dialect.
    files: ["src/backend/database/repositories/**/*.ts"],
    ignores: [
      // The two files whose job is to absorb these differences.
      "src/backend/database/repositories/returning.ts",
      "src/backend/database/repositories/mutation-result.ts",
    ],
    rules: {
      "no-restricted-syntax": [
        "error",
        {
          selector: "CallExpression[callee.property.name='returning']",
          message:
            "MySQL has no RETURNING. Use insertReturning/updateReturning/deleteReturning from ./returning.js, or rowsAffected() if you only need a count. Inside a proven sqlite-only branch, disable this rule with a comment saying so.",
        },
        {
          // `||` concatenates on SQLite and Postgres. On MySQL it is logical OR
          // unless the server runs with PIPES_AS_CONCAT, so a folder path built
          // this way silently became 0. Use CONCAT, which all three agree on.
          selector:
            "TaggedTemplateExpression[tag.name='sql'] TemplateElement[value.raw=/\\|\\|/]",
          message:
            "`||` is logical OR on MySQL, not concatenation. Use CONCAT(...).",
        },
        {
          // Postgres and SQLite spell it ON CONFLICT; MySQL spells it ON
          // DUPLICATE KEY and names no columns, so drizzle's mysql-core has no
          // onConflictDoUpdate at all — another TypeError, not a bad query.
          selector: "CallExpression[callee.property.name='onConflictDoUpdate']",
          message:
            "MySQL has no ON CONFLICT. Use upsert() from ./returning.js.",
        },
        {
          // better-sqlite3 puts these on a write result; node-postgres and
          // mysql2 do not, so reading them directly yields undefined — and
          // Number(undefined) is NaN, which reaches the database as the string
          // "NaN" and fails an integer column. Three call sites did exactly
          // this and only broke on Postgres.
          selector:
            "MemberExpression[property.name=/^(lastInsertRowid|changes)$/]",
          message:
            "lastInsertRowid and changes are better-sqlite3 only. Use insertedId() or rowsAffected() from ./mutation-result.js.",
        },
      ],
    },
  },
]);
