import { AssertPredicate, AssertionError } from 'node:assert';
import { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process';

type Code = 0 | 1;

type Configs$1 = {
    /**
     * Filter by path to match only the files that should be performed.
     *
     * @default /\.(test|spec)\./i
     */
    filter?: RegExp;
    /**
     * Exclude by path to match only the files that should be performed.
     *
     * @default undefined
     */
    exclude?: RegExp | RegExp[];
};

type ProcessAssertionOptions = {
    message?: string | Error;
    defaultMessage?: string;
    actual?: string;
    expected?: string;
    throw?: boolean;
    hideDiff?: boolean;
};
type AssertionMessage = ProcessAssertionOptions['message'];
type AssertValue = (value: unknown, message?: AssertionMessage) => void;
type AssertEqual = (actual: unknown, expected: unknown, message?: AssertionMessage) => void;
type AssertMatch = (value: string, regExp: RegExp, message?: AssertionMessage) => void;
type AsyncBlock = (() => Promise<unknown>) | Promise<unknown>;
type AssertThrows = {
    (block: () => unknown, message?: AssertionMessage): void;
    (block: () => unknown, error: AssertPredicate, message?: AssertionMessage): void;
};
type AssertRejects = {
    (block: AsyncBlock, message?: AssertionMessage): Promise<void>;
    (block: AsyncBlock, error: AssertPredicate, message?: AssertionMessage): Promise<void>;
};

declare const backgroundColor: {
    readonly white: 7;
    readonly black: 40;
    readonly grey: 100;
    readonly red: 41;
    readonly green: 42;
    readonly yellow: 43;
    readonly blue: 44;
    readonly magenta: 45;
    readonly cyan: 46;
    readonly brightRed: 101;
    readonly brightGreen: 102;
    readonly brightYellow: 103;
    readonly brightBlue: 104;
    readonly brightMagenta: 105;
    readonly brightCyan: 106;
};

type DescribeOptions = {
    background?: keyof typeof backgroundColor | boolean;
    /** @default "☰" */
    icon?: string;
};
type Describe = {
    (message: string, cb: AsyncTestCb): Promise<void>;
    (message: string, cb: TestCb): void;
    (cb: AsyncTestCb): Promise<void>;
    (cb: TestCb): void;
    (message: string, options?: DescribeOptions): void;
};

declare const timespan: Timespan;
declare const VERSION = "0.0.0-placeholder";

declare const results: {
    passed: number;
    failed: number;
    skipped: number;
    todo: number;
};

type PluginContext = {
    readonly configs: Configs;
    readonly runtime: Runtime;
    readonly cwd: string;
    readonly configFile: string | undefined;
    readonly runAsOnly: boolean;
    readonly results: typeof results;
    readonly timespan: typeof timespan;
    readonly reporter: ReturnType<ReporterPlugin>;
};
type PokuPlugin = {
    /** Plugin name */
    name?: string;
    /** Modify the command array before spawning a test file process */
    runner?: (command: string[], file: string) => string[];
    /** Run before the test suite begins */
    setup?: (context: PluginContext) => void | Promise<void>;
    /** Run after the test suite completes */
    teardown?: (context: PluginContext) => void | Promise<void>;
    /** Enable IPC channel for child processes */
    ipc?: boolean;
    /** Called after each test file process is spawned */
    onTestProcess?: (child: ChildProcess, file: string) => void;
    /** Intercept file discovery. Return the file paths to use */
    discoverFiles?: (paths: string[], context: PluginContext) => string[] | Promise<string[]>;
};
type Results = {
    code: number;
    timespan: Timespan;
    results: typeof results;
};
type Path = {
    absolute: string;
    relative: string;
};
type ReporterPlugin = (configs?: Configs) => {
    onRunStart: () => void;
    onDescribeAsTitle: (title: string, options?: DescribeOptions) => void;
    onDescribeStart: (options: {
        title?: string;
    }) => void;
    onDescribeEnd: (options: {
        duration: number;
        success?: boolean;
        title?: string;
    }) => void;
    onItStart: (options: {
        title?: string;
    }) => void;
    onItEnd: (options: {
        duration: number;
        success?: boolean;
        title?: string;
    }) => void;
    onAssertionSuccess: (options: {
        message: string;
    }) => void;
    onAssertionFailure: (options: {
        assertOptions: ProcessAssertionOptions;
        error: AssertionError;
    }) => void;
    onSkipFile: (options: {
        message: string;
    }) => void;
    onSkipModifier: (options: {
        message: string;
    }) => void;
    onTodoModifier: (options: {
        message: string;
    }) => void;
    onFileStart: (options: {
        path: Path;
    }) => void;
    onFileResult: (options: {
        status: boolean;
        path: Path;
        duration: number;
        output?: string;
    }) => void;
    onRunResult: (options: Results) => void;
    onExit: (options: Results) => void;
};
type ReporterEvents = Partial<ReturnType<ReporterPlugin>>;
type InspectCLIResult = {
    stdout: string;
    stderr: string;
    exitCode: number;
    process: ChildProcessWithoutNullStreams;
    PID: number;
    kill: () => Promise<void>;
};
type ScopeHook = {
    createHolder: () => {
        scope: unknown;
    };
    runScoped: (holder: {
        scope: unknown;
    }, fn: (params?: Record<string, unknown>) => Promise<unknown> | unknown) => Promise<void>;
};

type CustomString = string & NonNullable<unknown>;
type DenoOptions = {
    allow?: string[];
    deny?: string[];
};
type Runtime = 'node' | 'bun' | 'deno';
type Reporter = 'poku' | 'focus' | 'dot' | 'compact' | 'classic' | ReporterPlugin | CustomString;
type Configs = {
    /**
     * By setting `true`, **Poku** won't exit the process and will return the exit code (`0` or `1`)
     *
     * @default false
     */
    noExit?: boolean;
    /**
     * This option overwrites all `log` settings
     *
     * @default false
     */
    debug?: boolean;
    /**
     * This option overwrites the `debug` settings
     *
     * @default false
     */
    quiet?: boolean;
    /**
     * Determines the mode of test execution
     *
     * @default false
     */
    sequential?: boolean;
    /**
     * Controls process isolation for test files
     *
     * - `'process'` (default): each test file runs in a separate child process
     * - `'none'`: all test files run in the same process (useful for debugging with `--inspect`)
     *
     * @default 'process'
     */
    isolation?: 'none' | 'process' | (string & NonNullable<unknown>);
    /**
     * Stops the tests at the first failure.
     *
     * @default false
     */
    failFast?: boolean;
    /**
     * Limits the number of tests running concurrently
     *
     * @default (availableParallelism() || cpus().lenght)
     */
    concurrency?: number;
    /**
     * Sets the maximum time in milliseconds that each test file is allowed to run
     *
     * @default undefined
     */
    timeout?: number;
    /**
     * @default "poku"
     */
    reporter?: Reporter;
    /**
     * You can use this option to run a **callback** or a **file** before each test file on your suite
     *
     * ```ts
     * beforeEach(() => myFunc())
     * ```
     *
     * ```ts
     * beforeEach(async () => await myAsyncFunc())
     * ```
     */
    beforeEach?: () => unknown | Promise<unknown>;
    /**
     * You can use this option to run a **callback** or a **file** after each test file on your suite
     *
     * ```ts
     * afterEach(() => myFunc())
     * ```
     *
     * ```ts
     * afterEach(async () => await myAsyncFunc())
     * ```
     */
    afterEach?: () => unknown | Promise<unknown>;
    deno?: DenoOptions;
    /**
     * Plugins to extend Poku's behavior
     *
     * @default undefined
     */
    plugins?: PokuPlugin[];
    /**
     * Only run tests whose title matches the given regex pattern
     *
     * @default undefined
     */
    testNamePattern?: RegExp;
    /**
     * Skip tests whose title matches the given regex pattern
     *
     * @default undefined
     */
    testSkipPattern?: RegExp;
} & Configs$1;
type Timespan = {
    started: Date;
    finished: Date;
    duration: number;
};
type CliConfigs = {
    /** Default: searches for _`.test.`_ and `.spec.` files, but you can customize it */
    include?: string | string[];
    /** Reads an environment file and sets the environment variables */
    envFile?: string;
    /** Terminates the specified ports, port ranges and process IDs */
    kill?: {
        /** Terminates the specified ports before running the test suite */
        port?: [number];
        /** Terminates the specified port range before running the test suite */
        range?: [number, number][];
        /** Terminates the specified processes before running the test suite */
        pid?: [number];
    };
};
type ConfigFile = Omit<Configs, 'noExit'> & CliConfigs;
type Poku = {
    (targetPaths: string | string[], configs: Configs & {
        noExit: true;
    }): Promise<Code>;
    (targetPaths: string | string[], configs?: Configs): Promise<undefined>;
};
type TestCb = (params?: Record<string, unknown>) => unknown | Promise<unknown>;
type AsyncTestCb = (params?: Record<string, unknown>) => Promise<unknown>;

declare const onSigint: () => void;
declare const poku: Poku;

export { VERSION, onSigint, poku };
export type { AssertEqual, AssertMatch, AssertRejects, AssertThrows, AssertValue, AssertionMessage, AsyncTestCb, Code, ConfigFile, Configs$1 as Configs, Configs as Configs$1, Describe, InspectCLIResult, PluginContext, PokuPlugin, ReporterEvents, ReporterPlugin, ScopeHook, TestCb };
