import bundleAnalyzer from "@next/bundle-analyzer"
import { dirname, resolve } from "path"
import { fileURLToPath } from "url"

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
})

const __dirname = dirname(fileURLToPath(import.meta.url))

/** @type {import("next").NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: "/(.*)",
        headers: [
          { key: "X-Frame-Options", value: "DENY" },
          { key: "X-Content-Type-Options", value: "nosniff" },
          { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
          { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
          {
            key: "Strict-Transport-Security",
            value: "max-age=63072000; includeSubDomains; preload",
          },
          {
            key: "Content-Security-Policy",
            value: [
              "default-src 'self'",
              "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://widget.intercom.io https://js.intercomcdn.com https://client.crisp.chat https://settings.crisp.chat",
              "style-src 'self' 'unsafe-inline' https://client.crisp.chat",
              "img-src 'self' data: blob: https://avatars.githubusercontent.com https://github.com https://*.intercomcdn.com https://*.crisp.chat https://image.crisp.chat",
              "font-src 'self' data: https://client.crisp.chat",
              "connect-src 'self' https://*.intercom.io https://api-iam.intercom.io wss://*.intercom.io https://*.crisp.chat wss://*.crisp.chat https://*.sentry.io https://*.ingest.us.sentry.io https://us.i.posthog.com https://us.posthog.com",
              "frame-src 'self' https://intercom-sheets.com https://game.crisp.chat",
              "media-src 'self' https://*.intercomcdn.com",
              "worker-src 'self' blob:",
            ].join("; "),
          },
        ],
      },
    ]
  },
  cacheComponents: true,
  cacheLife: {
    dashboard: {
      stale: 60,        // 1 minute — serve stale while revalidating
      revalidate: 300,  // 5 minutes — background revalidation interval
      expire: 3600,     // 1 hour — hard expiry
    },
    frequent: {
      stale: 30,        // 30 seconds
      revalidate: 60,   // 1 minute
      expire: 600,      // 10 minutes
    },
  },
  transpilePackages: ["@codeflash-ai/common"],
  webpack: (config, { isServer }) => {
    config.watchOptions = {
      poll: 1000,
      aggregateTimeout: 300,
    }

    // Suppress known-harmless "Critical dependency" warnings from OpenTelemetry
    // and require-in-the-middle. These packages use dynamic require() for runtime
    // monkey-patching — webpack can't statically analyze them but they work fine.
    // Root cause: @sentry/nextjs → @sentry/node → @opentelemetry/instrumentation.
    config.ignoreWarnings = [
      ...(config.ignoreWarnings || []),
      { module: /@opentelemetry\/instrumentation/ },
      { module: /require-in-the-middle/ },
    ]

    // Handle web-tree-sitter's Node.js module imports in browser.
    // fallback handles static require(); alias handles dynamic import()
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        fs: false,
        "fs/promises": false,
        path: false,
        module: false,
      }
      config.resolve.alias = {
        ...config.resolve.alias,
        module: false,
      }
    }

    return config
  },
  turbopack: {
    root: __dirname,
    resolveAlias: {
      // Stub Node.js built-ins that web-tree-sitter tries to import in the browser.
      // Uses { browser: ... } so aliases only apply to client bundles, not SSR.
      'fs': { browser: './src/lib/empty-shim.js' },
      'fs/promises': { browser: './src/lib/empty-shim.js' },
      'path': { browser: './src/lib/empty-shim.js' },
      'module': { browser: './src/lib/empty-shim.js' },
    },
  },
  serverExternalPackages: [
    "@anthropic-ai/sdk",
    "sharp",
    "posthog-node",
    "@opentelemetry/api",
    "@opentelemetry/sdk-node",
    "@opentelemetry/auto-instrumentations-node",
    "@opentelemetry/instrumentation",
    "@prisma/instrumentation",
    "@sentry/opentelemetry",
    "@sentry/node",
    "require-in-the-middle",
    "@fastify/otel",
  ],
  experimental: {
    // Tree-shake barrel exports for these heavy packages. Without this,
    // importing a single icon from lucide-react or a single component from
    // chart.js pulls the entire library into the bundle.
    optimizePackageImports: [
      "lucide-react",
      "date-fns",
      "react-syntax-highlighter",
      "chart.js",
      "react-chartjs-2",
      "motion",
      "zod",
      "react-hook-form",
      "@hookform/resolvers",
      "react-markdown",
      "remark-gfm",
      "sonner",
      "react-resizable-panels",
      "@radix-ui/react-dialog",
      "@radix-ui/react-select",
      "@radix-ui/react-tabs",
      "@radix-ui/react-tooltip",
      "@radix-ui/react-toast",
      "chartjs-plugin-datalabels",
      "marked",
      "prism-react-renderer",
    ],
    serverActions: {
      allowedOrigins: ["app.codeflash.ai", "localhost:3000"],
      bodySizeLimit: '5mb', // Increased from default 1mb to handle large PR creation payloads
    },
    // NOTE: turbopackRemoveUnused{Imports,Exports} are NOT enabled — they
    // break @opentelemetry/api barrel re-exports and Next.js internal ESM
    // modules (same class of bug as turbopackTreeShaking + @sentry/core below).
    // turbopackRemoveUnusedImports requires turbopackRemoveUnusedExports.
    turbopackInferModuleSideEffects: true,
    // Scope hoisting: collapses module wrappers for smaller output
    turbopackScopeHoisting: true,
    // NOTE: turbopackTreeShaking is NOT enabled — it fragments modules into
    // "internal parts" which breaks @sentry/core's ESM cross-references
    // (withScope, withErrorInstrumentation exports disappear). Re-test when
    // Turbopack or Sentry fixes the incompatibility.
    // Persist compiled artifacts between CI builds
    turbopackFileSystemCacheForBuild: true,
    // Client-side router cache: avoid refetching on back-navigation
    staleTimes: {
      dynamic: 30,
      static: 180,
    },
  },
  typescript: {
    // Type-checking is split into a separate `npm run type-check` step.
    // This cuts ~16s off `next build` (was 60% of build time).
    ignoreBuildErrors: true,
  },
  // Optimize for production stability
  poweredByHeader: false,
  compress: true,
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "avatars.githubusercontent.com",
      },
      {
        protocol: "https",
        hostname: "github.com",
      },
    ],
    formats: ['image/avif', 'image/webp'],
  },
}

import { withSentryConfig } from "@sentry/nextjs"

// Only upload source maps when SENTRY_AUTH_TOKEN is set (CI/deploy).
// Skipping this shaves significant time off local builds.
const withSentry = process.env.SENTRY_AUTH_TOKEN
  ? (config) => withSentryConfig(
      config,
      {
        silent: true,
        org: "codeflash-ai",
        project: "webapp",
      },
      {
        widenClientFileUpload: true,
        tunnelRoute: "/monitoring",
        hideSourceMaps: true,
        disableLogger: true,
        automaticVercelMonitors: false,
      },
    )
  : (config) => config

export default withBundleAnalyzer(withSentry(nextConfig))
