import { Observable, Subject } from 'rxjs';
import { AuthenticationResponse, AuthenticatedUserSession } from '@studiohyperdrive/types-auth';
import * as i0 from '@angular/core';
import { Type, OnDestroy, TemplateRef, PipeTransform, Provider, EnvironmentProviders } from '@angular/core';
import { Route, CanActivateFn } from '@angular/router';
import { HttpInterceptorFn, HttpRequest, HttpClient, HttpContext } from '@angular/common/http';

/**
 * An interface for the routes used in an application that has uses the NgxAuthenticationAbstractService
 */
interface NgxAuthenticatedRoute<FeatureType extends string = string, PermissionType extends string = string> extends Route {
    data?: {
        /**
         * The features for the NgxHasFeatureGuard
         */
        feature?: FeatureType | FeatureType[];
        /**
         * Whether all features should be provided, by default true, for the NgxHasFeatureGuard
         */
        shouldHaveAllFeatures?: boolean;
        /**
         * The permissions for the NgxHasPermissionGuard
         */
        permission?: PermissionType | PermissionType[];
        /**
         * Whether all permissions should be provided, by default true, for the NgxHasPermissionGuard
         */
        shouldHaveAllPermissions?: boolean;
        /**
         * Whether the user should be authenticated, for the NgxIsAuthenticatedGuard
         */
        shouldBeAuthenticated?: boolean;
        /**
         * The location to redirect to if one of the guards conditions isn't met
         */
        redirect?: string[];
        /**
         * Remaining additional properties
         */
        [key: string]: unknown;
    };
}
type NgxAuthenticatedRoutes = NgxAuthenticatedRoute[];

type NgxAuthenticationStatus = 'unset' | 'signed-in' | 'signed-out';

type NgxAuthenticationResponseFeature<AuthenticationResponseType extends AuthenticationResponse<unknown>> = AuthenticationResponseType['session']['features'] extends (infer FeatureKey)[] ? FeatureKey : never;

/**
 * The configuration of the authentication handlers
 */
interface NgxAuthenticationConfiguration {
    /**
     * The provided implementation of the NgxAuthenticationAbstractService
     */
    service: Type<NgxAuthenticationAbstractService>;
    /**
     * An optional set of configuration to provide when the NgxAuthenticatedHttpClient needs to be used
     */
    httpClientConfiguration?: NgxAuthenticatedHttpClientConfiguration;
}
interface NgxAuthenticatedHttpClientConfiguration {
    /**
     * An optional list of interceptors that will be provided to the HttpClient
     */
    interceptors?: HttpInterceptorFn[];
    /**
     * A base url generator function that will be run at injection time used by any request made by the NgxAuthenticatedHttpClient
     */
    baseUrl?: () => string;
    /**
     * An optional handler for each authenticated API request made by the NgxAuthenticatedHttpClient
     */
    authenticatedCallHandler?: (request: HttpRequest<unknown>) => HttpRequest<unknown>;
}

/**
 * An abstract service used by the directives, guards and other components of @studiohyperdrive/ngx-auth
 *
 * @template AuthenticationResponseType - The type of authentication response
 * @template SignInDataType - The data type used to sign in a user
 * @template SignoutDataType - The data type used to sign out a user
 * @template SignOutResponseType - The data type you get when signing out a user
 */
declare abstract class NgxAuthenticationAbstractService<AuthenticationResponseType extends AuthenticationResponse<unknown> = AuthenticationResponse<any>, SignInDataType = any, SignoutDataType = any, SignOutResponseType = void> {
    /**
     * A subject to store the authentication response if no other state implementation was provided
     */
    private readonly authenticationResponseSubject;
    /**
     * A subject to store whether we've authenticated already
     */
    private readonly authenticationStatusSubject;
    /**
     * A subject to store global features that are available for all users, regardless of their authenticated state
     */
    private readonly globalFeaturesSubject;
    /**
     * Whether an authentication attempt has been made
     */
    readonly hasAuthenticated$: Observable<boolean>;
    /**
     * Whether the user is authenticated
     */
    readonly isAuthenticated$: Observable<boolean>;
    /**
     * The call required to sign in a user
     *
     * @param signInData - The data needed to sign in a user
     */
    protected abstract signInUser(signInData: SignInDataType): Observable<AuthenticationResponseType>;
    /**
     * The call required to sign out a user
     *
     * @param signoutDataType - Optional data needed to sign out a user
     */
    protected abstract signOutUser(signoutDataType?: SignoutDataType): Observable<SignOutResponseType>;
    /**
     * Stores the authentication response in the state
     *
     * @param response - The authentication response
     */
    protected storeAuthenticationResponse(response: AuthenticationResponseType): void;
    /**
     * Returns the authentication response from the state
     */
    protected getAuthenticationResponse(): Observable<AuthenticationResponseType>;
    /**
     * The authenticated user
     */
    get user$(): Observable<AuthenticationResponseType['user']>;
    /**
     * The session of the authenticated user
     */
    get session$(): Observable<AuthenticationResponseType['session']>;
    /**
     * The metadata of the authenticated user
     */
    get metadata$(): Observable<AuthenticationResponseType['metadata']>;
    /**
     * Signs in a user and stores the authentication response
     *
     * @param signInData - The data needed to sign in a user
     */
    signIn(signInData: SignInDataType): Observable<void>;
    /**
     * Signs out a user and removes the stored authentication response
     *
     * @param signoutDataType - Optional data needed to sign out a use
     */
    signOut(signoutDataType?: SignoutDataType): Observable<SignOutResponseType>;
    /**
     * Returns whether the user has the required features.
     *
     * @param requiredFeatures - An array of required features
     * @param shouldHaveAllFeatures - Whether all features in the array are required, by default true
     */
    hasFeature(requiredFeatures: NgxAuthenticationResponseFeature<AuthenticationResponseType>[], shouldHaveAllFeatures?: boolean): Observable<boolean>;
    /**
     * Sets a set of global features that are always present, regardless of the authenticated state of the user
     *
     * @param  features - A list of features
     */
    setGlobalFeatures(features: NgxAuthenticationResponseFeature<AuthenticationResponseType>[]): void;
    /**
     * Returns whether the user has the required permissions.
     *
     * @param requiredPermissions - An array of required permissions
     * @param shouldHaveAllPermissions - Whether all permissions in the array are required, by default true
     */
    hasPermission(requiredPermissions: AuthenticationResponseType['session']['permissions'], shouldHaveAllPermissions?: boolean): Observable<boolean>;
    /**
     * Returns a session or an empty session depending on the authenticated state
     */
    private getSession;
}

/**
 * A directive that will render a part of the template based on whether the required feature(s) are provided.
 *
 * Based upon `*ngIf`. See https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts
 */
declare class NgxHasFeatureDirective<FeatureType extends string> implements OnDestroy {
    private readonly templateRef;
    private readonly viewContainer;
    private readonly authenticationService;
    private readonly cdRef;
    /**
     * The destroyed state of the directive
     */
    private destroyed$;
    /**
     * The needed templateRefs
     */
    private thenTemplateRef;
    private thenViewRef;
    private elseTemplateRef;
    private elseViewRef;
    /**
     * The (list of) feature(s) we need to check
     */
    private feature;
    /**
     * Whether the feature should be enabled
     */
    private shouldHaveFeature;
    /**
     * Whether all features should be enabled
     */
    private shouldHaveAllFeatures;
    /**
     * A feature or list of features the item should have
     */
    set ngxHasFeature(feature: FeatureType | FeatureType[]);
    /**
     * The else template in case the feature is not enabled
     */
    set ngxHasFeatureElse(ngTemplate: TemplateRef<any>);
    /**
     * Whether the feature should be enabled, by default this is true
     */
    set ngxHasFeatureShouldHaveFeature(shouldHaveFeatureEnabled: boolean);
    /**
     * Whether all features should be enabled, by default this is true
     */
    set ngxHasFeatureShouldHaveAllFeatures(shouldHaveAllFeatures: boolean);
    constructor();
    ngOnDestroy(): void;
    /**
     * Updates the view and hides/renders the template as needed
     */
    private updateView;
    /**
     * Dispose the current subscription
     */
    private dispose;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxHasFeatureDirective<any>, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<NgxHasFeatureDirective<any>, "[ngxHasFeature]", never, { "ngxHasFeature": { "alias": "ngxHasFeature"; "required": false; }; "ngxHasFeatureElse": { "alias": "ngxHasFeatureElse"; "required": false; }; "ngxHasFeatureShouldHaveFeature": { "alias": "ngxHasFeatureShouldHaveFeature"; "required": false; }; "ngxHasFeatureShouldHaveAllFeatures": { "alias": "ngxHasFeatureShouldHaveAllFeatures"; "required": false; }; }, {}, never, never, true, never>;
}

/**
 * A directive that will render a part of the template based on whether the required permissions(s) are provided.
 *
 * Based upon `*ngIf`. See https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts
 */
declare class NgxHasPermissionDirective<PermissionType extends string> implements OnDestroy {
    private viewContainer;
    private readonly authenticationService;
    private readonly cdRef;
    /**
     * The destroyed state of the directive
     */
    private destroyed$;
    /**
     * The needed templateRefs
     */
    private thenTemplateRef;
    private thenViewRef;
    private elseTemplateRef;
    private elseViewRef;
    /**
     * The (list of) permission(s) we need to check
     */
    private permission;
    /**
     * Whether the permission should be enabled
     */
    private shouldHavePermission;
    /**
     * Whether all permissions should be enabled
     */
    private shouldHaveAllPermissions;
    /**
     * A permission or list of permissions the item should have
     */
    set ngxHasPermission(permission: PermissionType | PermissionType[]);
    /**
     * The else template in case the permission is not enabled
     */
    set ngxHasPermissionElse(ngTemplate: TemplateRef<any>);
    /**
     * Whether the permission should be enabled, by default this is true
     */
    set ngxHasPermissionShouldHavePermission(shouldHavePermissionEnabled: boolean);
    /**
     * Whether all permissions should be enabled, by default this is true
     */
    set ngxHasPermissionShouldHaveAllPermissions(shouldHaveAllPermissions: boolean);
    constructor();
    ngOnDestroy(): void;
    /**
     * Updates the view and hides/renders the template as needed
     */
    private updateView;
    /**
     * Dispose the current subscription
     */
    private dispose;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxHasPermissionDirective<any>, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<NgxHasPermissionDirective<any>, "[ngxHasPermission]", never, { "ngxHasPermission": { "alias": "ngxHasPermission"; "required": false; }; "ngxHasPermissionElse": { "alias": "ngxHasPermissionElse"; "required": false; }; "ngxHasPermissionShouldHavePermission": { "alias": "ngxHasPermissionShouldHavePermission"; "required": false; }; "ngxHasPermissionShouldHaveAllPermissions": { "alias": "ngxHasPermissionShouldHaveAllPermissions"; "required": false; }; }, {}, never, never, true, never>;
}

/**
 *  * A directive that will render a part of the template based on whether the user is authenticated.
 *
 * Based upon `*ngIf`. See https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts
 */
declare class NgxIsAuthenticatedDirective implements OnDestroy {
    private readonly authenticationService;
    private viewContainer;
    /**
     * The destroyed state of the directive
     */
    private destroyed$;
    /**
     * The needed templateRefs
     */
    private thenTemplateRef;
    private thenViewRef;
    private elseTemplateRef;
    private elseViewRef;
    /**
     * Whether the user has to be authenticated
     */
    private shouldBeAuthenticated;
    constructor();
    /**
     * Whether the user has to be authenticated
     */
    set ngxIsAuthenticated(authenticated: boolean);
    /**
     * The else template in case the condition is not matched
     */
    set ngxIsAuthenticatedElse(ngTemplate: TemplateRef<any>);
    ngOnDestroy(): void;
    private updateView;
    /**
     * Dispose the current subscription
     */
    private dispose;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxIsAuthenticatedDirective, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<NgxIsAuthenticatedDirective, "[ngxIsAuthenticated]", never, { "ngxIsAuthenticated": { "alias": "ngxIsAuthenticated"; "required": false; }; "ngxIsAuthenticatedElse": { "alias": "ngxIsAuthenticatedElse"; "required": false; }; }, {}, never, never, true, never>;
}

/**
 * Check if we can route to this route based on the provided feature
 *
 * @param  routeSnapshot - The provided route snapshot
 */
declare const NgxHasFeatureGuard: CanActivateFn;

/**
 * Check if we can route to this route based on the provided permission
 *
 * @param  routeSnapshot - The provided route snapshot
 */
declare const NgxHasPermissionGuard: CanActivateFn;

/**
 * Check if we can route to this route based on the provided permission
 *
 * @param  routeSnapshot - The provided route snapshot
 */
declare const NgxIsAuthenticatedGuard: CanActivateFn;

/**
 * A pipe that returns whether a (list of) feature(s) has been provided
 */
declare class NgxHasFeaturePipe<FeatureType extends string> implements PipeTransform, OnDestroy {
    private readonly authenticationService;
    private readonly cdRef;
    /**
     * Subject to hold the destroyed state of the current observable
     */
    private destroyed$;
    /**
     * The latest value of the Observable, whether or not the feature is provided
     */
    private hasFeature;
    /**
     * Instance of the change detector ref, implemented like this according to the async pipe implementation
     * https://github.com/angular/angular/blob/main/packages/common/src/pipes/async_pipe.ts
     */
    private changeDetectorRef;
    constructor();
    ngOnDestroy(): void;
    /**
     * Returns whether or not a feature is provided for the environment
     *
     * @param feature - The provided feature
     */
    transform(feature: FeatureType | FeatureType[]): boolean;
    /**
     * Handles the changeDetection, latest value and dispose of the hasFeature observable
     *
     * @param observable - The hasFeature observable
     */
    private subscribe;
    /**
     * Dispose of the feature observable when existing
     */
    private dispose;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxHasFeaturePipe<any>, never>;
    static ɵpipe: i0.ɵɵPipeDeclaration<NgxHasFeaturePipe<any>, "ngxHasFeature", true>;
}

/**
 * A pipe that returns whether a (list of) permission(s) has been provided
 */
declare class NgxHasPermissionPipe<PermissionType extends string> implements PipeTransform, OnDestroy {
    private readonly authenticationService;
    private readonly cdRef;
    /**
     * Subject to hold the destroyed state of the current observable
     */
    private destroyed$;
    /**
     * The latest value of the Observable, whether or not the permission is provided
     */
    private hasPermission;
    /**
     * Instance of the change detector ref, implemented like this according to the async pipe implementation
     * https://github.com/angular/angular/blob/main/packages/common/src/pipes/async_pipe.ts
     */
    private changeDetectorRef;
    constructor();
    ngOnDestroy(): void;
    /**
     * Returns whether or not a permission is provided for the environment
     *
     * @param permission - The provided permission
     */
    transform(permission: PermissionType | PermissionType[]): boolean;
    /**
     * Handles the changeDetection, latest value and dispose of the hasPermission observable
     *
     * @param observable - The hasPermission observable
     */
    private subscribe;
    /**
     * Dispose of the permission observable when existing
     */
    private dispose;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxHasPermissionPipe<any>, never>;
    static ɵpipe: i0.ɵɵPipeDeclaration<NgxHasPermissionPipe<any>, "ngxHasPermission", true>;
}

/**
 * Configures the provided implementation of the NgxAuthenticationAbstract service to the application
 *
 * @param configuration - The configuration with the provided service implementation
 */
declare const provideNgxAuthenticationConfiguration: (configuration: NgxAuthenticationConfiguration) => Provider | EnvironmentProviders[];

/**
 * Returns a mock version of the authentication service
 *
 * @param  configuration - The configuration of the mock
 */
declare const NgxAuthenticationServiceMock: <AuthenticationResponseType extends AuthenticationResponse<any> = AuthenticationResponse<any>>(configuration: {
    hasFeatureSpy: unknown;
    hasPermissionSpy: unknown;
    signInSpy: unknown;
    signOutSpy: unknown;
    authenticationResponse: Subject<AuthenticationResponseType>;
    hasAuthenticated: Subject<NgxAuthenticationStatus>;
}) => any;

/**
 * Returns a mock authentication response
 */
declare const NgxAuthenticationResponseMock: AuthenticationResponse<{
    name: string;
}, AuthenticatedUserSession<'A' | 'B', 'Admin' | 'User'>, {
    requestPassword: boolean;
}>;

declare const NgxMockAuthenticatedHttpClient: (configuration: {
    download?: unknown;
    get?: unknown;
    patch?: unknown;
    put?: unknown;
    delete?: unknown;
    post?: unknown;
}) => {
    get: unknown;
    download: unknown;
    delete: unknown;
    patch: unknown;
    post: unknown;
    put: unknown;
};

/**
 * An opinionated wrapper of the HttpClient providing easy ways to make authenticated and unauthenticated calls
 */
declare class NgxAuthenticatedHttpClient {
    private readonly httpClient;
    private baseUrl;
    constructor();
    /**
     * Adds a base-url to every request
     * @param {string} url - The url of the request
     */
    private handleUrl;
    /**
     * Constructs a GET request to the provided API
     *
     * @param  url - The url of the API
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    get<DataType = unknown>(url: string, params?: Parameters<HttpClient['get']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<DataType>;
    /**
     * Constructs a GET request tailored to downloading to the provided API
     *
     * @param  url - The url of the API
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    download(url: string, params?: Parameters<HttpClient['get']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<{
        fileType: string;
        blob: Blob;
    }>;
    /**
     * Constructs a DELETE request to the provided API
     *
     * @param  url - The url of the API
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    delete<DataType = void>(url: string, params?: Parameters<HttpClient['delete']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<DataType>;
    /**
     * Constructs a POST request to the provided API
     *
     * @param  url - The url of the API
     * @param body - The body we wish to send
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    post<DataType = void>(url: string, body: any, params?: Parameters<HttpClient['post']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<DataType>;
    /**
     * Constructs a PUT request to the provided API
     *
     * @param  url - The url of the API
     * @param body - The body we wish to send
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    put<DataType = void>(url: string, body?: any, params?: Parameters<HttpClient['put']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<DataType>;
    /**
     * Constructs a PATCH request to the provided API
     *
     * @param  url - The url of the API
     * @param body - The body we wish to send
     * @param params - An optional set of params we wish to send to the API
     * @param withCredentials - Whether the call is made by an authenticated user, by default true
     * @param context - An optional HTTPContext
     */
    patch<DataType = void>(url: string, body: any, params?: Parameters<HttpClient['patch']>[1]['params'], withCredentials?: boolean, context?: HttpContext): Observable<DataType>;
    static ɵfac: i0.ɵɵFactoryDeclaration<NgxAuthenticatedHttpClient, never>;
    static ɵprov: i0.ɵɵInjectableDeclaration<NgxAuthenticatedHttpClient>;
}

export { NgxAuthenticatedHttpClient, NgxAuthenticationAbstractService, NgxAuthenticationResponseMock, NgxAuthenticationServiceMock, NgxHasFeatureDirective, NgxHasFeatureGuard, NgxHasFeaturePipe, NgxHasPermissionDirective, NgxHasPermissionGuard, NgxHasPermissionPipe, NgxIsAuthenticatedDirective, NgxIsAuthenticatedGuard, NgxMockAuthenticatedHttpClient, provideNgxAuthenticationConfiguration };
export type { NgxAuthenticatedHttpClientConfiguration, NgxAuthenticatedRoute, NgxAuthenticatedRoutes, NgxAuthenticationConfiguration, NgxAuthenticationResponseFeature, NgxAuthenticationStatus };
