import { OutputOptions, Plugin, LogLevel, RollupLog } from 'rollup';
import { RollupReplaceOptions } from '@rollup/plugin-replace';
import { RollupJsonOptions } from '@rollup/plugin-json';
import { RollupNodeResolveOptions } from '@rollup/plugin-node-resolve';
import { RollupAliasOptions, Alias } from '@rollup/plugin-alias';
import { TransformOptions } from 'esbuild';
import { Options as Options$1 } from 'rollup-plugin-dts';

interface TransformersChunk {
    esbuild?: TransformOptions;
    resolve?: RollupNodeResolveOptions | true;
    replace?: RollupReplaceOptions;
    json?: RollupJsonOptions | true;
    alias?: RollupAliasOptions;
}
interface TransformersDeclaration {
    dts?: Options$1;
    alias?: RollupAliasOptions;
}

interface EntryBase {
    /**
     * Specifies the format of the generated module.
     *
     * @default 'esm'
     */
    format?: OutputOptions['format'];
    /**
     * Specifies the module IDs, or regular expressions to match module IDs,
     * that should remain external to the bundle.
     *
     * If not specified, infers the IDs from the global `options.externals` option.
     *
     * @default undefined
     */
    externals?: (string | RegExp)[];
    /**
     * Specifies the string to be inserted at the beginning of the module.
     *
     * @default undefined
     */
    banner?: OutputOptions['banner'];
    /**
     * Specifies the string to be inserted at the end of the module.
     *
     * @default undefined
     */
    footer?: OutputOptions['footer'];
    /**
     * Specifies the code at the beginning that goes inside any _format-specific_ wrapper.
     *
     * @default undefined
     */
    intro?: OutputOptions['intro'];
    /**
     * Specifies the code at the end that goes inside any _format-specific_ wrapper.
     *
     * @default undefined
     */
    outro?: OutputOptions['outro'];
    /**
     * Maps external module IDs to paths.
     *
     * @default undefined
     */
    paths?: OutputOptions['paths'];
    /**
     * Specifies custom filters that will display only certain log messages.
     *
     * @default undefined
     */
    logFilter?: string[];
    /**
     * Specifies `rollup` plugins.
     *
     * Adding custom plugins disables all built-in `transformers` for full customization.
     *
     * @default undefined
     */
    plugins?: Plugin[];
}
interface EntryChunk extends EntryBase {
    /**
     * Specifies the path of the build source.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     { input: './src/index.ts' }, // => './dist/index.mjs'
     *   ]
     * })
     * ```
     */
    input?: string;
    /**
     * Specifies the path of the transformed file.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     {
     *       input: './src/index.ts',
     *       output: './out/index.js', // => './out/index.js'
     *     },
     *   ]
     * })
     * ```
     *
     * @default undefined
     */
    output?: string;
    /**
     * Specifies the built-in `transformers` options.
     *
     * Available transformers:
     *
     * - `esbuild`
     * - `resolve`
     * - `replace`
     * - `json`
     * - `alias`
     *
     * @default undefined
     */
    transformers?: TransformersChunk;
    /**
     * Specifies the global variable name that representing exported bundle.
     *
     * Intended for `umd/iife` formats.
     *
     * @default undefined
     */
    name?: OutputOptions['name'];
    /**
     * Specifies global _module ID_ and _variable name_ pairs necessary for external imports.
     *
     * Intended for `umd/iife` formats.
     *
     * @default undefined
     */
    globals?: OutputOptions['globals'];
    /**
     * Specifies whether to extend the global variable defined by the `name` option.
     *
     * Intended for `umd/iife` formats.
     */
    extend?: OutputOptions['extend'];
    /**
     * Minifies the generated code if enabled.
     *
     * @default undefined
     */
    minify?: boolean;
    declaration?: never;
    dts?: never;
    copy?: never;
    template?: never;
}
interface EntryDeclaration extends EntryBase {
    /**
     * Specifies the path of the TypeScript `declaration` build source.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     { dts: './src/types.ts' }, // => './dist/types.d.mts'
     *   ]
     * })
     * ```
     */
    dts?: string;
    /**
     * Specifies the path of the TypeScript `declaration` build source.
     *
     * Also, it is possible to use `dts` alias.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     { declaration: './src/types.ts' }, // => './dist/types.d.mts'
     *   ]
     * })
     * ```
     */
    declaration?: string;
    /**
     * Specifies the path of the TypeScript  transformed `declaration` file.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     {
     *       dts: './src/types.ts',
     *       output: './out/types.d.ts', // => './out/types.d.ts'
     *     },
     *   ]
     * })
     * ```
     *
     * @default undefined
     */
    output?: string;
    /**
     * Specifies the built-in `transformers` options.
     *
     * Available transformers:
     *
     * - `dts`
     * - `alias`
     *
     * @default undefined
     */
    transformers?: TransformersDeclaration;
    input?: never;
    copy?: never;
    template?: never;
    name?: never;
    globals?: never;
    extend?: never;
    minify?: never;
}
interface CopyOptions {
    /**
     * Specifies the path of the source.
     */
    input: string | string[];
    /**
     * Specifies the path of the destination directory.
     */
    output: string;
    /**
     * Copy directories recursively.
     *
     * @default true
     */
    recursive?: boolean;
    /**
     * Filters copied `files/directories`.
     *
     * Returns `true` to copy the item, `false` to ignore it.
     *
     * @default undefined
     */
    filter?(source: string, destination: string): boolean;
}
interface EntryCopy {
    /**
     * Copies the single `file` or entire `directory` structure from source to destination, including subdirectories and files.
     *
     * This can be very useful for copying some assets that don't need a transformation process, but a simple copy paste feature.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     {
     *       copy: {
     *         input: './src/path/file.ts', // or ['path-dir', 'path-file.ts', ...]
     *         output: './dist/out', // path to output dir
     *       }
     *     }
     *   ]
     * })
     * ```
     *
     * @default undefined
     */
    copy?: CopyOptions;
    input?: never;
    declaration?: never;
    dts?: never;
    template?: never;
    name?: never;
    globals?: never;
    extend?: never;
    minify?: never;
}
interface EntryTemplate {
    /**
     * Specifies the content of the `template` file.
     *
     * Provides the ability to dynamically inject template content during the build phase.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     {
     *       template: `// TypeScript code...`,
     *       output: './dist/template.ts',
     *     },
     *   ]
     * })
     * ```
     */
    template: string;
    /**
     * Specifies the path of the transformed `template` file.
     */
    output: string;
    input?: never;
    declaration?: never;
    dts?: never;
    copy?: never;
    name?: never;
    globals?: never;
    extend?: never;
    minify?: never;
}
type EntryOptions = EntryChunk | EntryDeclaration | EntryCopy | EntryTemplate;

interface Options {
    /**
     * Specifies the bundle's entry points.
     *
     * It allows you to manually set all build entries and adjust options for each one individually.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     { input: './src/index.ts' }, // => './dist/index.mjs'
     *     { dts: './src/types.ts' }, // => './dist/types.d.mts'
     *     // ...
     *   ]
     * })
     * ```
     */
    entries: EntryOptions[];
    /**
     * Specifies the output directory for production bundle.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   outDir: 'output',
     * })
     * ```
     *
     * @default 'dist'
     */
    outDir?: string;
    /**
     * Specifies the module IDs, or regular expressions to match module IDs,
     * that should remain external to the bundle.
     *
     * IDs and regexps from this option are applied globally to all entries.
     *
     * Also, it is possible to define externals individually per entry (`entry.externals`).
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   externals: ['id-1', 'id-2', /regexp/],
     * })
     * ```
     *
     * @default [/^node:/, /^@types/, /^@rollup/, /^@hypernym/, /^rollup/, ...pkg.dependencies]
     */
    externals?: (string | RegExp)[];
    /**
     * Provides a powerful hooking system to further expand bundling mode.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'build:end': async (options, buildStats) => {
     *       // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    hooks?: HooksOptions;
    /**
     * Specifies prefixes that will resolve imports with custom paths.
     *
     * Enables these `alias` by default:
     *
     * ```ts
     * // Imports module from './src/utils/index.js'
     * import { module } from '@/utils' // @
     * import { module } from '~/utils' // ~
     * ```
     *
     * Also, it is possible to completely override the default aliases by setting custom ones.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   alias: [
     *     { find: /^#/, replacement: resolve('./src') },
     *   ]
     * })
     * ```
     *
     * Now imports can be used like this:
     *
     * ```ts
     * // Imports module from './src/utils/index.js'
     * import { module } from '#/utils' // #
     * ```
     *
     * @default undefined
     */
    alias?: Alias[];
    /**
     * Specifies the minification for all `chunk` entries.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   minify: true,
     * })
     * ```
     *
     * It can also be set per entry.
     *
     * ```ts
     * export default defineConfig({
     *   entries: [
     *     {
     *       input: './src/index.ts',
     *       minify: true,
     *     },
     *   ],
     * })
     * ```
     *
     * @default undefined
     */
    minify?: boolean;
}

interface BuildLogs {
    level: LogLevel;
    log: RollupLog;
}
interface BuildEntryStats {
    /**
     * The root path of the project.
     */
    cwd: string;
    /**
     * Module output path.
     */
    path: string;
    /**
     * Module size.
     */
    size: number;
    /**
     * Build time of individual module.
     */
    buildTime: number;
    /**
     * Module format.
     */
    format: string;
    /**
     * List of warnings from build plugins.
     */
    logs: BuildLogs[];
}
interface BuildStats {
    /**
     * The root path of the project.
     */
    cwd: string;
    /**
     * Final bundle size.
     */
    size: number;
    /**
     * Total bundle build time.
     */
    buildTime: number;
    /**
     * List of generated bundle modules.
     */
    files: BuildEntryStats[];
}
type PickEntryChunkOptions = 'input' | 'name' | 'globals' | 'extend' | 'minify' | 'transformers';
type PickEntryDtsOptions = 'declaration' | 'dts' | 'transformers';
interface BuildEntryOptions extends EntryBase, Pick<EntryChunk, PickEntryChunkOptions>, Pick<EntryDeclaration, PickEntryDtsOptions> {
    /**
     * Specifies the path of the transformed file.
     *
     * @default undefined
     */
    output?: string;
    /**
     * Specifies options for default plugins.
     *
     * @default undefined
     */
    transformers?: TransformersChunk & TransformersDeclaration;
    /**
     * Specifies list of default plugins.
     */
    defaultPlugins: Plugin[];
}

interface HooksOptions {
    /**
     * Called at the beginning of bundling.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'bundle:start': async (options) => {
     *       // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'bundle:start'?: (options: Options) => void | Promise<void>;
    /**
     * Called at the beginning of building.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'build:start': async (options, stats) => {
     *       // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'build:start'?: (options: Options, stats: BuildStats) => void | Promise<void>;
    /**
     * Called on each entry just before the build process.
     *
     * Provides the ability to customize entry options before they are passed to the next phase.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'build:entry:start': async (entry, stats) => {
     *      // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'build:entry:start'?: (entry: BuildEntryOptions, stats: BuildEntryStats) => void | Promise<void>;
    /**
     * Called on each entry right after the build process is completed.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'build:entry:end': async (entry, stats) => {
     *      // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'build:entry:end'?: (entry: BuildEntryOptions, stats: BuildEntryStats) => void | Promise<void>;
    /**
     * Called right after building is complete.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'build:end': async (options, stats) => {
     *       // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'build:end'?: (options: Options, stats: BuildStats) => void | Promise<void>;
    /**
     * Called right after bundling is complete.
     *
     * @example
     *
     * ```ts
     * export default defineConfig({
     *   hooks: {
     *     'bundle:end': async (options) => {
     *       // ...
     *     }
     *   }
     * })
     * ```
     *
     * @default undefined
     */
    'bundle:end'?: (options: Options) => void | Promise<void>;
}

interface ConfigLoader {
    options: Options;
    path: string;
}

/**
 * List of global defaults for externals.
 *
 * @example
 *
 * ```ts
 * import { externals } from '@hypernym/bundler'
 *
 * export default defineConfig({
 *   entries: [
 *     {
 *       input: './src/index.ts',
 *       externals: [...externals, 'id', /regexp/]
 *     },
 *   ]
 * })
 * ```
 */
declare const externals: RegExp[];
/**
 * `Hyperbundler` automatically detects custom configuration from the project root that can override or extend the build behavior.
 *
 * Configuration file also accepts `.js`, `.mjs`, `.ts`, `.mts` formats.
 *
 * @example
 *
 * ```ts
 * import { defineConfig } from '@hypernym/bundler'
 *
 * export default defineConfig({
 *   // ...
 * })
 * ```
 */
declare function defineConfig(options: Options): Options;

/**
 * Resolves external module IDs into custom paths.
 *
 * @example
 *
 * ```ts
 * import { defineConfig, resolvePaths } from '@hypernym/bundler'
 *
 * export default defineConfig({
 *   entries: [
 *     {
 *       input: './src/index.ts',
 *       externals: [/^@\/path/],
 *       paths: resolvePaths([
 *         // replaces `@/path` with `./path/index.mjs`
 *         { find: /^@\/path/, replacement: './path/index.mjs', }
 *       ]),
 *     },
 *   ]
 * })
 * ```
 */
declare function resolvePaths(options: ResolvePathsOptions[]): (id: string) => string;

interface ResolvePathsOptions {
    find: string | RegExp;
    replacement: string;
}

export { defineConfig, externals, resolvePaths };
export type { BuildLogs, BuildStats, ConfigLoader, CopyOptions, EntryBase, EntryChunk, EntryCopy, EntryDeclaration, EntryOptions, EntryTemplate, HooksOptions, Options, ResolvePathsOptions, TransformersChunk, TransformersDeclaration };
