import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { defineConfig } from 'tsdown'

const here = dirname(fileURLToPath(import.meta.url))
const distDir = resolve(here, 'dist')

const tsconfig = '../../tsconfig.base.json'

const deps = {
  // Keep transitive external type graphs out of dts bundling.
  // `vite`/`esbuild`/`postcss` are pulled in via the kit client's
  // `declare module 'vite'` augmentation and contain
  // rolldown-incompatible re-exports that would otherwise fail dts
  // generation with dozens of MISSING_EXPORT errors.
  neverBundle: [
    'vite',
    'esbuild',
    'postcss',
    'rolldown',
    /^@rolldown\//,
    /^@oxc-project\//,
    'terser',
    '@jridgewell/trace-mapping',
  ],
  // `whenexpr` is runtime-only bundled (see `onlyBundle` below); its
  // declaration file mixes type-only and value named exports
  // (`export { type WhenExpression, evaluateWhen, ... }`) in a way that
  // trips up rolldown's dts bundler when it tries to inline the type
  // graph too (spuriously drops the `type` modifier off the merged
  // re-export, then can't find `WhenExpression` as a value export). Leave
  // `whenexpr`'s types external and let dts consumers resolve them
  // straight from the published package.
  dts: {
    neverBundle: ['whenexpr'],
  },
  onlyBundle: [
    'acorn',
    'bundle-name',
    'default-browser',
    'default-browser-id',
    'define-lazy-prop',
    'get-port-please',
    'immer',
    'is-docker',
    'is-in-ssh',
    'is-inside-container',
    'is-wsl',
    'launch-editor',
    'mlly',
    'obug',
    'ohash',
    'open',
    'p-limit',
    'perfect-debounce',
    'picocolors',
    'powershell-utils',
    'run-applescript',
    'shell-quote',
    'structured-clone-es',
    'tinyexec',
    'ua-parser-modern',
    'whenexpr',
    'wsl-utils',
    'yocto-queue',
  ],
}

// Shared by the runtime client build and the combined dts build below.
const clientEntries = {
  'client/index': 'src/client/index.ts',
  'utils/agent-tool-name': 'src/utils/agent-tool-name.ts',
  'utils/colors': 'src/utils/colors.ts',
  'utils/crypto-token': 'src/utils/crypto-token.ts',
  'utils/events': 'src/utils/events.ts',
  'utils/hash': 'src/utils/hash.ts',
  'utils/nanoid': 'src/utils/nanoid.ts',
  'utils/promise': 'src/utils/promise.ts',
  'utils/simple-schema': 'src/utils/simple-schema.ts',
  'utils/scope': 'src/utils/scope.ts',
  'utils/shared-state': 'src/utils/shared-state.ts',
  'utils/streaming-channel': 'src/utils/streaming-channel.ts',
  'utils/structured-clone': 'src/utils/structured-clone.ts',
  'utils/when': 'src/utils/when.ts',
}

// Shared by the runtime server build and the combined dts build below.
const serverEntries = {
  'index': 'src/index.ts',
  'constants': 'src/constants.ts',
  'types/index': 'src/types/index.ts',
  'rpc/index': 'src/rpc/index.ts',
  'rpc/client': 'src/rpc/client.ts',
  'rpc/dump': 'src/rpc/dump/index.ts',
  'rpc/server': 'src/rpc/server.ts',
  'rpc/transports/ws-bun': 'src/rpc/transports/ws-bun.ts',
  'rpc/transports/ws-client': 'src/rpc/transports/ws-client.ts',
  'rpc/transports/ws-server': 'src/rpc/transports/ws-server.ts',
  'node/index': 'src/node/index.ts',
  'node/auth': 'src/node/auth/index.ts',
  'node/hub-internals': 'src/node/hub-internals/index.ts',
  'utils/launch-editor': 'src/utils/launch-editor.ts',
  'utils/open': 'src/utils/open.ts',
  'utils/serve-static': 'src/utils/serve-static.ts',
  'adapters/cac': 'src/adapters/cac.ts',
  'adapters/cli': 'src/adapters/cli.ts',
  'adapters/dev': 'src/adapters/dev.ts',
  'adapters/build': 'src/adapters/build.ts',
  'adapters/embedded': 'src/adapters/embedded.ts',
  'adapters/initiate': 'src/adapters/initiate.ts',
  'adapters/mcp': 'src/adapters/mcp/index.ts',
  'cli/main': 'src/cli/main.ts',
  'helpers/vite': 'src/helpers/vite.ts',
  'recipes/common-rpc-functions': 'src/recipes/common-rpc-functions.ts',
  'recipes/open-helpers': 'src/recipes/open-helpers.ts',
  'recipes/interactive-auth': 'src/recipes/interactive-auth.ts',
}

// Three configs:
//
// 1. Runtime client/agnostic build (`dts: false`). Independent rolldown
//    chunk graph so server-only imports like `devframe/rpc/transports/ws-server`
//    or `node:crypto` can't leak into browser-loaded outputs
//    (`client/index.mjs`, `utils/hash.mjs`, …). `clean: true` clears
//    dist/ before the server build appends.
// 2. Runtime server/node build (`dts: false`). `clean: false` appends to
//    the client output.
// 3. Combined dts build (`emitDtsOnly: true`). All entries live in a
//    single rolldown graph so shared modules — notably
//    `src/types/rpc-augments.ts` — produce exactly one declaration site.
//    This is what lets consumer `declare module 'devframe'` augmentations
//    propagate across every import chain.
export default defineConfig([
  {
    clean: true,
    platform: 'browser',
    tsconfig,
    deps,
    dts: false,
    // `platform: 'browser'` defaults to `.js`; force `.mjs` to match the
    // `packages/devframe/package.json` `exports` map.
    outExtensions: () => ({ js: '.mjs' }),
    entry: clientEntries,
    hooks: {
      'build:done': async () => {
        const { checkClientDist } = await import('./scripts/check-client-dist.ts')
        await checkClientDist({
          entries: [
            resolve(distDir, 'client/index.mjs'),
            resolve(distDir, 'utils/agent-tool-name.mjs'),
            resolve(distDir, 'utils/colors.mjs'),
            resolve(distDir, 'utils/crypto-token.mjs'),
            resolve(distDir, 'utils/events.mjs'),
            resolve(distDir, 'utils/hash.mjs'),
            resolve(distDir, 'utils/nanoid.mjs'),
            resolve(distDir, 'utils/promise.mjs'),
            resolve(distDir, 'utils/simple-schema.mjs'),
            resolve(distDir, 'utils/scope.mjs'),
            resolve(distDir, 'utils/shared-state.mjs'),
            resolve(distDir, 'utils/streaming-channel.mjs'),
            resolve(distDir, 'utils/structured-clone.mjs'),
            resolve(distDir, 'utils/when.mjs'),
          ],
          cwd: here,
        })
      },
    },
  },
  {
    clean: false,
    platform: 'node',
    tsconfig,
    deps,
    dts: false,
    entry: serverEntries,
  },
  {
    clean: false,
    platform: 'neutral',
    tsconfig,
    deps,
    dts: { emitDtsOnly: true },
    outExtensions: () => ({ dts: '.d.mts' }),
    entry: { ...clientEntries, ...serverEntries },
  },
])
