import { Provider, EnvironmentProviders, Type, ApplicationConfig, ApplicationRef, TypeProvider } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

type LazyModule<T> = () => Promise<T | {
    default: T;
}>;
type AngularProvider = Provider | EnvironmentProviders;
type LazyProvider = LazyModule<AngularProvider | Array<AngularProvider>>;
type LazyComponent = LazyModule<Type<unknown>>;
type FastProvider = AngularProvider | LazyProvider;
type FastComponent = Type<unknown> | LazyComponent;
type FastApplicationConfig = Omit<ApplicationConfig, 'providers'> & {
    providers: Array<FastProvider>;
};

/**
 * Dynamically loads the specified providers in the configuration and bootstraps an Angular application.
 *
 * This function uses the custom applicationBoostrap function argument to start an Angular application with providers
 * that are dynamically loaded and resolved. The application configuration can include providers that need to
 * be loaded asynchronously. This function handles resolving these providers and passing them to the custom bootstrap function.
 *
 * @param bootstrap - The Angular application's bootstrap function (typically `bootstrapApplication`).
 * @param rootComponent - The root component of the application, which should be of type `FastComponent`
 *                  (ie. Type<unknown> or lazy module that return this component).
 * @param options - (Optional) The application configuration, including the providers to be loaded. It should conform
 *                  to the `FastApplicationConfig` type. Providers can be `Provider`, `EnvironmentProviders`,
 *                  or lazy modules that return these providers.
 *
 * @returns A Promise that resolves to an `ApplicationRef` instance of the bootstrapped application. The bootstrap
 *          method is called with the root component and the updated configuration with the resolved providers.
 *
 * @example
 * ```typescript
 * import { AppComponent } from './app.component';
 * import { bootstrapApplication } from '@angular/platform-browser';
 * import { fast } from 'ngx-fastboot';
 *
 * fast(bootstrapApplication, AppComponent, {
 *   providers: [
 *     MyProvider,
 *     () => import('./my-provider.module'),
 *   ]
 * }).then(() => console.log('App is bootstrapped'))
 *   .catch(error => {
 *     console.error('Error bootstrapping the app', error);
 *   });
 * ```
 */
declare const fast: (bootstrap: typeof bootstrapApplication, rootComponent: FastComponent, options?: FastApplicationConfig) => Promise<ApplicationRef>;

/**
 * Dynamically loads the specified providers in the configuration and bootstraps an Angular application.
 *
 * This function start an Angular application with providers that are dynamically loaded and resolved.
 * The application configuration can include providers that need to be loaded asynchronously.
 * This function handles resolving these providers and passing them to the angular bootstrapApplication function.
 *
 * @param rootComponent - The root component of the application, which should be of type `FastComponent`
 *                  (ie. Type<unknown> or lazy module that return this component).
 * @param options - (Optional) The application configuration, including the providers to be loaded. It should conform
 *                  to the `FastApplicationConfig` type. Providers can be `Provider`, `EnvironmentProviders`,
 *                  or lazy modules that return these providers.
 *
 * @returns A Promise that resolves to an `ApplicationRef` instance of the bootstrapped application. The bootstrap
 *          method is called with the root component and the updated configuration with the resolved providers.
 *
 * @example
 * ```typescript
 * import { AppComponent } from './app.component';
 * import { fastBootstrapApplication } from 'ngx-fastboot';
 *
 * fastBootstrapApplication(AppComponent, {
 *   providers: [
 *     MyProvider,
 *     () => import('./my-provider.module'),
 *   ]
 * }).then(() => console.log('App is bootstrapped'))
 *   .catch(error => {
 *     console.error('Error bootstrapping the app', error);
 *   });
 * ```
 */
declare const fastBootstrapApplication: (rootComponent: FastComponent, options?: FastApplicationConfig) => Promise<ApplicationRef>;

declare const isTypeProvider: (value: FastProvider) => value is TypeProvider;

declare const loadModule: <T>(module: LazyModule<T>) => Promise<T>;

declare const resolveProvider: (provider: FastProvider) => Promise<Array<AngularProvider>>;

declare const resolveProviders: (providers: Array<FastProvider>) => Promise<Array<AngularProvider>>;

export { type AngularProvider, type FastApplicationConfig, type FastComponent, type FastProvider, type LazyComponent, type LazyModule, type LazyProvider, fast, fastBootstrapApplication, isTypeProvider, loadModule, resolveProvider, resolveProviders };
