/* eslint-env node */
import process from "node:process";

import js from "@eslint/js";
import nextPlugin from "@next/eslint-plugin-next";
import importX from "eslint-plugin-import-x";
import reactHooks from "eslint-plugin-react-hooks";
import sonarjs from "eslint-plugin-sonarjs";
import unicorn from "eslint-plugin-unicorn";
import globals from "globals";
import tseslint from "typescript-eslint";

const TS_FILES = ["**/*.{ts,tsx}"];
const BFF_TS_FILES = ["apps/bff/**/*.ts"];
const PACKAGES_TS_FILES = ["packages/**/*.ts"];
const PORTAL_FILES = ["apps/portal/**/*.{js,jsx,ts,tsx}"];

const withFiles = (configs, files) =>
  configs.map(config => ({
    ...config,
    files,
  }));

export default [
  // =============================================================================
  // Global ignores
  // =============================================================================
  {
    ignores: [
      "**/node_modules/**",
      "**/dist/**",
      "**/.next/**",
      "**/.turbo/**",
      "**/.cache/**",
      "**/.pnpm-store/**",
      "**/.typecheck/**",
      "**/build/**",
      "**/coverage/**",
      "**/next-env.d.ts",
      "**/prisma/**",
    ],
  },

  // =============================================================================
  // Base JS
  // =============================================================================
  js.configs.recommended,

  // =============================================================================
  // Loop safety & complexity limits (all files)
  // =============================================================================
  {
    files: TS_FILES,
    rules: {
      // Prevent infinite loops
      "for-direction": "error",
      "no-constant-condition": "error",
      "no-unmodified-loop-condition": "error",
      "no-unreachable-loop": "error",

      // Complexity limits
      complexity: ["warn", { max: 15 }],
      "max-depth": ["warn", { max: 4 }],
      "max-nested-callbacks": ["warn", { max: 3 }],
      "max-params": ["warn", { max: 4 }],
      "max-lines-per-function": ["warn", { max: 100, skipBlankLines: true, skipComments: true }],

      // Common mistakes
      "no-await-in-loop": "warn",
      "no-promise-executor-return": "error",
      "require-atomic-updates": "error",
    },
  },

  // =============================================================================
  // SonarJS: code smells & cognitive complexity
  // =============================================================================
  {
    files: TS_FILES,
    plugins: { sonarjs },
    rules: {
      "sonarjs/cognitive-complexity": ["warn", 15],
      "sonarjs/no-duplicate-string": ["warn", { threshold: 3 }],
      "sonarjs/no-identical-functions": "error",
      "sonarjs/no-collapsible-if": "warn",
      "sonarjs/no-redundant-jump": "error",
      "sonarjs/no-nested-switch": "error",
      "sonarjs/no-nested-template-literals": "warn",
      "sonarjs/prefer-single-boolean-return": "warn",
      "sonarjs/no-gratuitous-expressions": "error",
    },
  },

  // =============================================================================
  // Unicorn: modern JS patterns & footgun prevention
  // =============================================================================
  {
    files: TS_FILES,
    plugins: { unicorn },
    rules: {
      "unicorn/no-array-for-each": "warn",
      "unicorn/no-array-push-push": "warn",
      "unicorn/no-await-expression-member": "warn",
      "unicorn/no-for-loop": "warn",
      "unicorn/no-lonely-if": "warn",
      "unicorn/no-negated-condition": "warn",
      "unicorn/no-nested-ternary": "error",
      "unicorn/no-useless-undefined": "warn",
      "unicorn/prefer-array-find": "error",
      "unicorn/prefer-array-flat-map": "error",
      "unicorn/prefer-array-some": "error",
      "unicorn/prefer-at": "warn",
      "unicorn/prefer-includes": "error",
      "unicorn/prefer-number-properties": "error",
      "unicorn/prefer-optional-catch-binding": "warn",
      "unicorn/prefer-spread": "warn",
      "unicorn/prefer-string-slice": "error",
      "unicorn/throw-new-error": "error",
    },
  },

  // =============================================================================
  // Import-X: circular dependency prevention & import hygiene
  // =============================================================================
  {
    files: [...BFF_TS_FILES, ...PACKAGES_TS_FILES, ...PORTAL_FILES],
    plugins: { "import-x": importX },
    rules: {
      "import-x/no-cycle": ["error", { maxDepth: 3 }],
      "import-x/no-self-import": "error",
      "import-x/no-useless-path-segments": "warn",
      "import-x/no-duplicates": "error",
      "import-x/first": "error",
      "import-x/newline-after-import": "warn",
      "import-x/no-mutable-exports": "error",
    },
  },

  // =============================================================================
  // TypeScript (fast rules, no type information)
  // =============================================================================
  ...withFiles(tseslint.configs.recommended, TS_FILES),

  // =============================================================================
  // TypeScript (type-aware rules) — only where we want the cost
  // =============================================================================
  ...tseslint.configs.recommendedTypeChecked.map(config => ({
    ...config,
    files: [...BFF_TS_FILES, ...PACKAGES_TS_FILES],
    languageOptions: {
      ...(config.languageOptions || {}),
      parserOptions: {
        ...((config.languageOptions && config.languageOptions.parserOptions) || {}),
        projectService: true,
        tsconfigRootDir: process.cwd(),
      },
    },
  })),

  // =============================================================================
  // Backend + domain packages: sensible defaults
  // =============================================================================
  {
    files: ["packages/domain/**/*.ts"],
    rules: {
      "@typescript-eslint/consistent-type-imports": "error",
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
      ],
      "no-console": ["warn", { allow: ["warn", "error"] }],
      "no-restricted-imports": [
        "error",
        {
          patterns: [
            {
              group: ["#toolkit/whmcs", "#toolkit/whmcs/*"],
              message:
                "WHMCS provider utilities must not live under toolkit. Keep them under `packages/domain/common/providers/whmcs-utils/` and import via relative paths inside the domain package.",
            },
          ],
        },
      ],
    },
  },

  // =============================================================================
  // Shared packages: stricter safety
  // =============================================================================
  {
    files: PACKAGES_TS_FILES,
    rules: {
      "@typescript-eslint/no-redundant-type-constituents": "error",
      "@typescript-eslint/no-explicit-any": "error",
      "@typescript-eslint/no-unsafe-return": "error",
      "@typescript-eslint/no-unsafe-call": "error",
      "@typescript-eslint/no-unsafe-member-access": "error",
    },
  },

  // =============================================================================
  // Portal (Next.js)
  // =============================================================================
  {
    ...nextPlugin.configs["core-web-vitals"],
    files: PORTAL_FILES,
  },
  {
    files: ["apps/portal/**/*.{jsx,tsx}"],
    plugins: { "react-hooks": reactHooks },
    rules: {
      "react-hooks/rules-of-hooks": "error",
      "react-hooks/exhaustive-deps": "warn",
    },
  },
  {
    files: ["apps/portal/**/*.{ts,tsx}"],
    rules: {
      "@typescript-eslint/no-unused-vars": [
        "error",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
        },
      ],
      "@next/next/no-html-link-for-pages": "off",
      // Prevent console.log in production code - use logger instead
      "no-console": ["error", { allow: ["warn", "error"] }],
    },
  },

  // =============================================================================
  // Portal navigation guardrails
  // =============================================================================
  {
    files: ["apps/portal/src/app/(authenticated)/**/*.{ts,tsx}"],
    rules: {
      "no-restricted-syntax": [
        "error",
        {
          selector: "MemberExpression[object.name='window'][property.name='location']",
          message: "Use next/link or useRouter for navigation.",
        },
      ],
    },
  },
  {
    files: ["apps/portal/src/app/(authenticated)/layout.tsx"],
    rules: { "no-restricted-imports": "off" },
  },
  {
    files: ["apps/portal/src/app/(authenticated)/billing/invoices/[id]/page.tsx"],
    rules: { "no-restricted-syntax": "off" },
  },

  // =============================================================================
  // Architecture: import boundaries
  // =============================================================================
  {
    files: ["apps/portal/src/**/*.{ts,tsx}", "apps/bff/src/**/*.ts"],
    rules: {
      "no-restricted-imports": [
        "error",
        {
          paths: [
            {
              name: "@customer-portal/domain",
              message:
                "Do not import @customer-portal/domain (root). Use @customer-portal/domain/<module> instead.",
            },
          ],
          patterns: [
            {
              group: ["@customer-portal/domain/**/src/**"],
              message: "Import from @customer-portal/domain/<module> instead of internals.",
            },
            {
              group: ["@customer-portal/domain/*/*", "!@customer-portal/domain/*/providers"],
              message:
                "No deep @customer-portal/domain imports. Use @customer-portal/domain/<module> (or BFF-only: .../<module>/providers).",
            },
            {
              group: ["@customer-portal/domain/*/providers/*"],
              message:
                "Do not deep-import provider internals. Import from @customer-portal/domain/<module>/providers only.",
            },
          ],
        },
      ],
    },
  },

  // =============================================================================
  // Portal: hard boundary — must not import provider adapters/types
  // =============================================================================
  {
    files: ["apps/portal/src/**/*.{ts,tsx}"],
    rules: {
      "no-restricted-imports": [
        "error",
        {
          paths: [
            {
              name: "@customer-portal/domain",
              message:
                "Do not import @customer-portal/domain (root). Use @customer-portal/domain/<module> instead.",
            },
          ],
          patterns: [
            {
              group: ["@/hooks/*"],
              message:
                "Do not import from @/hooks. Use @/lib/hooks (app-level hooks) or feature hooks under src/features/<feature>/hooks.",
            },
            {
              group: ["@customer-portal/domain/**/src/**"],
              message: "Import from @customer-portal/domain/<module> instead of internals.",
            },
            {
              group: ["@customer-portal/domain/*/providers"],
              message:
                "Portal must not import provider adapters/types. Import normalized domain models from @customer-portal/domain/<module> instead.",
            },
            {
              group: ["@customer-portal/domain/*/*", "!@customer-portal/domain/*/providers"],
              message:
                "No deep @customer-portal/domain imports. Use @customer-portal/domain/<module> only.",
            },
            {
              group: ["@customer-portal/domain/*/providers/*"],
              message:
                "Do not deep-import provider internals. Import from @customer-portal/domain/<module>/providers only (BFF-only).",
            },
          ],
        },
      ],
    },
  },
  {
    files: ["apps/portal/src/app/(authenticated)/layout.tsx"],
    rules: { "no-restricted-imports": "off" },
  },

  // =============================================================================
  // BFF: stricter type safety (type-aware)
  // =============================================================================
  {
    files: BFF_TS_FILES,
    rules: {
      "@typescript-eslint/no-explicit-any": "error",
      "@typescript-eslint/no-unsafe-assignment": "error",
      "@typescript-eslint/no-unsafe-member-access": "error",
      "@typescript-eslint/no-unsafe-call": "error",
      "@typescript-eslint/no-unsafe-return": "error",
      "@typescript-eslint/no-unsafe-argument": "error",
      "@typescript-eslint/require-await": "error",
      "@typescript-eslint/no-floating-promises": "error",
      "@typescript-eslint/no-misused-promises": "error",
      "@typescript-eslint/promise-function-async": "warn",
      "@typescript-eslint/await-thenable": "error",
      // Prevent console.log in production code - use logger instead
      "no-console": ["error", { allow: ["warn", "error"] }],
    },
  },

  // =============================================================================
  // BFF controllers: request DTOs must come from shared domain schemas (no inline zod)
  // =============================================================================
  {
    files: ["apps/bff/src/modules/**/*.controller.ts"],
    rules: {
      "no-restricted-syntax": [
        "error",
        {
          selector: "ImportDeclaration[source.value='zod']",
          message:
            "Do not import zod in controllers. Put request/param/query schemas in @customer-portal/domain and use createZodDto(schema) with the global ZodValidationPipe.",
        },
      ],
    },
  },

  // =============================================================================
  // BFF Architecture: Controllers must use facades, not integration internals
  // See: docs/decisions/007-service-classification.md
  // Note: Set to "warn" for incremental adoption. Upgrade to "error" once violations are fixed.
  // =============================================================================
  {
    files: ["apps/bff/src/modules/**/*.controller.ts"],
    rules: {
      "no-restricted-imports": [
        "warn",
        {
          paths: [
            {
              name: "@customer-portal/domain",
              message:
                "Do not import @customer-portal/domain (root). Use @customer-portal/domain/<module> instead.",
            },
          ],
          patterns: [
            {
              group: ["@customer-portal/domain/**/src/**"],
              message: "Import from @customer-portal/domain/<module> instead of internals.",
            },
            {
              group: ["@customer-portal/domain/*/*", "!@customer-portal/domain/*/providers"],
              message:
                "No deep @customer-portal/domain imports. Use @customer-portal/domain/<module> (or BFF-only: .../<module>/providers).",
            },
            {
              group: ["@customer-portal/domain/*/providers/*"],
              message:
                "Do not deep-import provider internals. Import from @customer-portal/domain/<module>/providers only.",
            },
            {
              group: ["@bff/integrations/*/services/*", "@bff/integrations/*/connection/*"],
              message:
                "Controllers should not import integration services or connection internals directly. Import from @bff/integrations/*/facades/* instead (ADR-007).",
            },
          ],
        },
      ],
    },
  },

  // =============================================================================
  // BFF Architecture: Aggregators must be read-only (no mutation methods)
  // See: docs/decisions/007-service-classification.md
  // =============================================================================
  {
    files: [
      "apps/bff/src/aggregators/**/*.ts",
      "apps/bff/src/modules/me-status/me-status.service.ts",
      "apps/bff/src/modules/users/infra/user-profile.service.ts",
    ],
    rules: {
      "no-restricted-syntax": [
        "warn",
        {
          selector: "MethodDefinition[key.name=/^(create|update|delete|save|remove|add|set)[A-Z]/]",
          message:
            "Aggregators must be read-only. Mutation methods should be moved to orchestrators or services (ADR-007).",
        },
      ],
    },
  },

  // =============================================================================
  // BFF Architecture: Services must use Facades, not direct connection internals
  // This enforces the facade pattern for integration layer access
  // Target: HTTP client services in connection/ directories (e.g., whmcs-http-client.service.ts)
  // Note: Domain services like WhmcsClientService (customer operations) are allowed
  // =============================================================================
  {
    files: ["apps/bff/src/modules/**/*.service.ts"],
    rules: {
      "no-restricted-imports": [
        "error",
        {
          patterns: [
            {
              group: ["@bff/integrations/*/connection/**/*"],
              message:
                "Do not import connection internals (HTTP clients, etc.) directly. Use the facade from @bff/integrations/*/facades/* instead.",
            },
          ],
        },
      ],
    },
  },

  // =============================================================================
  // Node globals for tooling/config files
  // =============================================================================
  {
    files: [
      "*.config.*",
      "apps/portal/next.config.mjs",
      "config/**/*.{js,cjs,mjs}",
      "scripts/**/*.{js,cjs,mjs}",
      "apps/**/scripts/**/*.{js,cjs,mjs}",
    ],
    languageOptions: {
      globals: { ...globals.node },
    },
  },
];
