/*!
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
import { UninitView, View } from './rvx.js';
import { Falsy } from './rvx.js';
import { AsyncContext } from './rvx.async.js';
import { TagNameMap } from './rvx.js';

/**
 * Assert that the specified view is in a valid state.
 *
 * This can be used in development to assert the correctness of custom view implementations.
 *
 * ```tsx
 * import { View } from "rvx";
 * import { assertViewState } from "rvx/test";
 *
 * new View((setBoundary, self) => {
 *   ...
 *   assertViewState(self);
 *   ...
 * });
 * ```
 */
declare function assertViewState(view: UninitView): void;

interface PollFn<T> {
	(abort: AbortSignal): T | Falsy | Promise<T | Falsy>;
}
declare class PollTimeoutError extends Error {
}
/**
 * Repeatedly call a function until a truthy value is returned.
 *
 * + The function is called at most every event cycle.
 * + If a timeout occurs, a {@link PollTimeoutError} is thrown and the abort signal passed to the function is aborted with the same error.
 *
 * @param fn The function to run.
 * @param timeout An optional timeout.
 * @returns The first truthy value.
 */
declare function poll<T>(fn: PollFn<T>, timeout?: number): Promise<T>;

/**
 * Run an exclusive action for a specific purpose.
 *
 * @param key The key to identify the purpose.
 * @param action The action to run.
 */
declare function exclusive<T>(key: unknown, action: () => T | Promise<T>): Promise<T>;

interface AsyncTestContext {
	asyncCtx: AsyncContext;
	use: <T>(fn: () => T) => T;
}
type AsyncTestFn<T> = (ctx: AsyncTestContext) => Promise<T>;
declare function runAsyncTest<T>(fn: AsyncTestFn<T>): Promise<T>;

type TestFn<T> = () => T;
declare function runTest<T>(fn: TestFn<T>): T;

/**
 * The same as **querySelector**, but for {@link View views}.
 */
declare function querySelector<K extends keyof TagNameMap>(view: View, selector: K): TagNameMap[K] | null;
declare function querySelector<E extends Element = Element>(view: View, selector: string): E | null;
/**
 * The same as **querySelectorAll**, but for {@link View views}.
 */
declare function querySelectorAll<K extends keyof TagNameMap>(view: View, selector: K): TagNameMap[K][];
declare function querySelectorAll<E extends Element = Element>(view: View, selector: string): E[];

export { PollTimeoutError, assertViewState, exclusive, poll, querySelector, querySelectorAll, runAsyncTest, runTest };
export type { AsyncTestContext, AsyncTestFn, PollFn, TestFn };
