import { defineConfig } from 'electron-vite'
import { sentryVitePlugin } from '@sentry/vite-plugin'
import react from '@vitejs/plugin-react'
import { readFileSync } from 'fs'
import { resolve } from 'path'
import type { Plugin } from 'vite'

// Read all production dependencies from package.json
// so they get bundled into the main process output.
// This avoids pnpm symlink issues with electron-builder's asar packaging.
const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8'))
const prodDeps = Object.keys(pkg.dependencies || {})

// Fastify and its plugins rely on runtime module resolution that breaks when bundled.
const runtimeExternalDeps = new Set([
  'node-pty',
  'agent-teams-controller',
  'fastify',
  '@fastify/cors',
  '@fastify/static',
])

// node-pty is a native addon that cannot be bundled by Rollup.
// It must remain external and be loaded at runtime via require().
const bundledDeps = prodDeps.filter(d => !runtimeExternalDeps.has(d))

// Rollup plugin: stub out native .node addon imports with empty modules.
// ssh2 and cpu-features use optional native bindings that can't be bundled,
// but they have pure JS fallbacks when the native module isn't available.
function nativeModuleStub(): Plugin {
  const STUB_ID = '\0native-stub'
  const NODE_MODULE_RE = /\.node(?:\?.*)?$/
  return {
    name: 'native-module-stub',
    enforce: 'pre',
    resolveId(source) {
      if (NODE_MODULE_RE.test(source)) return `${STUB_ID}:${source}`
      return null
    },
    load(id) {
      if (id.startsWith(STUB_ID) || NODE_MODULE_RE.test(id)) return 'export default {}'
      return null
    }
  }
}

const sentrySourceMapTargets = {
  main: {
    assets: ['./dist-electron/main/**/*.{js,cjs,mjs,map}'],
    filesToDeleteAfterUpload: ['./dist-electron/main/**/*.map'],
  },
  renderer: {
    assets: ['./out/renderer/**/*.{js,cjs,mjs,map}'],
    filesToDeleteAfterUpload: ['./out/renderer/**/*.map'],
  },
} as const

const sourceMapSetting = process.env.AGENT_TEAMS_DISABLE_SOURCEMAPS === '1' ? false : 'hidden'

// Sentry source map upload - only active in CI when SENTRY_AUTH_TOKEN is set.
function createSentryPlugins(target: keyof typeof sentrySourceMapTargets): Plugin[] {
  if (!process.env.SENTRY_AUTH_TOKEN) return []

  return [
    sentryVitePlugin({
      org: process.env.SENTRY_ORG ?? 'quant-jump-pro',
      project: process.env.SENTRY_PROJECT ?? 'electron',
      authToken: process.env.SENTRY_AUTH_TOKEN,
      telemetry: false,
      release: { name: `agent-teams-ai@${pkg.version}` },
      sourcemaps: sentrySourceMapTargets[target],
    }) as Plugin,
  ]
}

export default defineConfig({
  main: {
    plugins: [
      nativeModuleStub(),
      ...createSentryPlugins('main'),
    ],
    define: {
      __APP_VERSION__: JSON.stringify(pkg.version),
      // Inject DSN at compile time - process.env.SENTRY_DSN is NOT available
      // at runtime in packaged Electron apps (only during CI build).
      'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN ?? ''),
    },
    resolve: {
      alias: {
        '@features': resolve(__dirname, 'src/features'),
        '@main': resolve(__dirname, 'src/main'),
        '@shared': resolve(__dirname, 'src/shared'),
        '@preload': resolve(__dirname, 'src/preload')
      }
    },
    build: {
      externalizeDeps: {
        exclude: bundledDeps
      },
      commonjsOptions: {
        strictRequires: [/node_modules\/.*ssh2\//],
      },
      sourcemap: sourceMapSetting,
      outDir: 'dist-electron/main',
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/main/index.ts'),
          'team-fs-worker': resolve(__dirname, 'src/main/workers/team-fs-worker.ts'),
          'task-change-worker': resolve(__dirname, 'src/main/workers/task-change-worker.ts'),
          'team-data-worker': resolve(__dirname, 'src/main/workers/team-data-worker.ts')
        },
        output: {
          // CJS format so bundled deps can use __dirname/require.
          // Use .cjs extension since package.json has "type": "module".
          format: 'cjs',
          entryFileNames: '[name].cjs',
          // Set UV_THREADPOOL_SIZE before any module code runs.
          // Must be in the banner because ESM→CJS hoists imports above top-level code.
          // On Windows, fs.watch({recursive:true}) occupies a UV pool thread per watcher;
          // with 3+ watchers + concurrent fs/DNS/spawn, the default 4 threads deadlock.
          banner: `if(!process.env.UV_THREADPOOL_SIZE){process.env.UV_THREADPOOL_SIZE='24'}`
        }
      }
    }
  },
  preload: {
    resolve: {
      alias: {
        '@features': resolve(__dirname, 'src/features'),
        '@preload': resolve(__dirname, 'src/preload'),
        '@shared': resolve(__dirname, 'src/shared'),
        '@main': resolve(__dirname, 'src/main')
      }
    },
    build: {
      outDir: 'dist-electron/preload',
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/preload/index.ts')
        },
        output: {
          format: 'cjs',
          entryFileNames: '[name].js'
        }
      }
    }
  },
  renderer: {
    cacheDir: resolve(__dirname, 'node_modules/.vite/electron-renderer'),
    optimizeDeps: {
      include: ['@codemirror/language-data'],
      exclude: ['@claude-teams/agent-graph']
    },
    define: {
      __APP_VERSION__: JSON.stringify(pkg.version),
      // Pass SENTRY_DSN to renderer as VITE_SENTRY_DSN (Vite replaces at compile time)
      'import.meta.env.VITE_SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN ?? ''),
    },
    resolve: {
      alias: {
        '@features': resolve(__dirname, 'src/features'),
        '@renderer': resolve(__dirname, 'src/renderer'),
        '@shared': resolve(__dirname, 'src/shared'),
        '@main': resolve(__dirname, 'src/main'),
        '@radix-ui/react-compose-refs': resolve(
          __dirname,
          'src/renderer/vendor/radixComposeRefs.ts'
        ),
        '@claude-teams/agent-graph': resolve(__dirname, 'packages/agent-graph/src/index.ts')
      }
    },
    plugins: [react(), ...createSentryPlugins('renderer')],
    build: {
      sourcemap: sourceMapSetting,
      rollupOptions: {
        input: {
          index: resolve(__dirname, 'src/renderer/index.html')
        }
      }
    }
  }
})
