import * as i0 from '@angular/core';
import { InjectionToken, TemplateRef, ViewContainerRef, ModuleWithProviders, Injector, Type } from '@angular/core';
import { AXPLogoConfig, AXPOptionsData, AXPExpressionEvaluatorScopeProvider, AXPExpressionEvaluatorScopeProviderContext } from '@acorex/platform/core';
import { CanActivateFn } from '@angular/router';
import { Observable } from 'rxjs';

interface AXPEdition {
    id: string;
    title: string;
    description?: string;
}
interface AXPApplication {
    id: string;
    name: string;
    title?: string;
    version?: string;
    edition?: AXPEdition;
    description?: string;
    logo?: AXPLogoConfig;
}

interface AXPTenant {
    id: string;
    name: string;
    title: string;
    description?: string;
    logo?: AXPLogoConfig;
}

interface AXPUser {
    id: string;
    name: string;
    title: string;
    avatar?: string;
}

declare class AXPSessionContext {
    private _user;
    get user(): AXPUser | null;
    private _tenant;
    get tenant(): AXPTenant | null;
    private _application;
    get application(): AXPApplication | null;
    constructor(context: {
        user: AXPUser | null;
        tenant: AXPTenant | null;
        application: AXPApplication | null;
    });
}
declare enum AXPSessionStatus {
    Authenticated = "authenticated",
    Unauthenticated = "unauthenticated",
    Unauthorized = "unauthorized",
    Authorized = "authorized",
    Expired = "expired",
    SignedOut = "signedOut"
}

interface AXPApplicationLoader {
    getList(context: AXPSessionContext): Promise<AXPApplication[]>;
}
declare const AXP_APPLICATION_LOADER: InjectionToken<AXPApplicationLoader>;

interface AXPTenantLoader {
    getList(context: AXPSessionContext): Promise<AXPTenant[]>;
}
declare const AXP_TENANT_LOADER: InjectionToken<AXPTenantLoader>;

declare class AXPPermissionDirective {
    private templateRef;
    private viewContainer;
    private hasView;
    private subscription;
    private sessionService;
    constructor(templateRef: TemplateRef<any>, viewContainer: ViewContainerRef);
    set permission(permissionKeys: string | string[] | null);
    set permissionElse(elseTemplateRef: TemplateRef<any>);
    ngOnDestroy(): void;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPPermissionDirective, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<AXPPermissionDirective, "[permission]", never, { "permission": { "alias": "permission"; "required": false; }; "permissionElse": { "alias": "permissionElse"; "required": false; }; }, {}, never, never, false, never>;
}

declare const AXPPermissionGuard: CanActivateFn;

type AXPPermission = string;
interface AXPPermissionGroupDefinition {
    name: string;
    title: string;
    description?: string;
    permissions: AXPPermissionDefinition[];
}
type AXPPermissionDefinition = {
    name: AXPPermission;
    title: string;
    description?: string;
    children: AXPPermissionDefinition[];
    /**
     * Required features for this permission to be available.
     * Format: Array of feature names (e.g., ['PlatformManagement.menu-customization'])
     * If any required feature is not enabled, this permission will be filtered out.
     */
    requiredFeatures?: string[];
};

interface AXPPermissionLoader {
    getList(context: AXPSessionContext): Promise<AXPPermission[]>;
}
declare const AXP_PERMISSION_LOADER: InjectionToken<AXPPermissionLoader>;

declare class AXPPermissionDefinitionProviderContext {
    private builders;
    addGroup(name: string, title: string, description?: string): AXPPermissionDefinitionGroupBuilder;
    getGroupDefinitions(): AXPPermissionGroupDefinition[];
    findGroup(name: string): AXPPermissionDefinitionGroupBuilder | undefined;
    isGroupDefined(name: string): boolean;
}
declare class AXPPermissionDefinitionGroupBuilder {
    private context;
    private _group;
    get group(): AXPPermissionGroupDefinition;
    constructor(context: AXPPermissionDefinitionProviderContext, group: AXPPermissionGroupDefinition);
    addPermission(name: string, title: string, description?: string, requiredFeatures?: string[]): AXPPermissionDefinitionBuilder;
    endGroup(): AXPPermissionDefinitionProviderContext;
    findPermission(path: string): AXPPermissionDefinition | undefined;
    findGroup(name: string): AXPPermissionDefinitionGroupBuilder | undefined;
}
declare class AXPPermissionDefinitionBuilder {
    private groupBuilder;
    private permission;
    constructor(groupBuilder: AXPPermissionDefinitionGroupBuilder, permission: AXPPermissionDefinition);
    addChild(name: string, title: string, description?: string, requiredFeatures?: string[]): AXPPermissionDefinitionBuilder;
    /**
     * Set required features for this permission.
     * @param features - Array of feature names (e.g., ['PlatformManagement.menu-customization'])
     */
    requireFeatures(...features: string[]): AXPPermissionDefinitionBuilder;
    endPermission(): AXPPermissionDefinitionGroupBuilder;
}

interface AXPPermissionDefinitionProvider {
    define(context: AXPPermissionDefinitionProviderContext): Promise<void>;
}
declare const AXP_PERMISSION_DEFINITION_PROVIDER: InjectionToken<AXPPermissionDefinitionProvider[]>;
declare class AXPPermissionDefinitionService {
    private providers;
    private sessionService;
    private cache;
    private load;
    /**
     * Filter permissions based on required features.
     * Removes permissions that have required features that are not enabled.
     */
    private filterByFeatures;
    /**
     * Recursively filter permissions and their children based on required features.
     */
    private filterPermissions;
    reload(): Promise<void>;
    getGroups(): Promise<AXPPermissionGroupDefinition[]>;
    getPermissions(): Promise<AXPPermissionDefinition[]>;
    getGroup(name: string): Promise<AXPPermissionGroupDefinition | null>;
    getPermission(name: string): Promise<AXPPermissionDefinition | null>;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPPermissionDefinitionService, never>;
    static ɵprov: i0.ɵɵInjectableDeclaration<AXPPermissionDefinitionService>;
}

interface AXPBaseCredentials {
    strategy: string;
    [key: string]: string;
}
interface AXPTokenResult {
    accessToken: string;
    expiresIn?: string | null;
    refreshToken?: string;
    idToken?: string;
    tenant?: AXPTenant | null;
    application?: AXPApplication | null;
}
interface AXPSignInResult {
    succeed: boolean;
    data?: {
        accessToken: string;
        idToken?: string | null;
        expiresIn?: string | null;
        refreshToken: string;
        user: AXPUser;
        tenant?: AXPTenant | null;
        application?: AXPApplication | null;
    };
}
declare abstract class AXPAuthStrategy {
    abstract get name(): string;
    abstract signin(credentials: AXPBaseCredentials): Promise<AXPSignInResult | void>;
    abstract signout(): Promise<void>;
    abstract refreshToken(context: AXPSessionContext): Promise<AXPSignInResult>;
    abstract updateToken(params?: {
        [key: string]: any;
    }): Promise<AXPSignInResult | void>;
}
interface AXPSessionData {
    accessToken: string;
    refreshToken: string;
    idToken: string | null;
    strategy: string;
    user?: AXPUser | null;
    tenant?: AXPTenant | null;
    application?: AXPApplication | null;
    expiresIn?: string | null;
}

interface AXPFeature {
    name: string;
    title: string;
    description?: string;
    value?: any;
    interface?: {
        type: string;
        options?: AXPOptionsData;
    };
}

interface AXPFeatureLoader {
    getList(context: AXPSessionContext): Promise<AXPFeature[]>;
}
declare const AXP_FEATURE_LOADER: InjectionToken<AXPFeatureLoader>;

declare class AXPFeatureDirective {
    private templateRef;
    private viewContainer;
    private hasView;
    private subscription;
    private sessionService;
    constructor(templateRef: TemplateRef<any>, viewContainer: ViewContainerRef);
    set feature(featureKeys: string | string[] | null);
    set featureElse(elseTemplateRef: TemplateRef<any>);
    ngOnDestroy(): void;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPFeatureDirective, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<AXPFeatureDirective, "[feature]", never, { "feature": { "alias": "feature"; "required": false; }; "featureElse": { "alias": "featureElse"; "required": false; }; }, {}, never, never, false, never>;
}

declare const AXPFeatureGuard: CanActivateFn;

/**
 * Interface for feature checkers that can override feature enablement results.
 * Checkers receive the feature keys, current context, and base result,
 * and can return a modified result based on custom logic.
 */
interface AXPFeatureChecker {
    /**
     * Checks and potentially overrides the feature enablement result.
     * @param keys - The feature keys being checked
     * @param context - Current session context (user, tenant, application)
     * @param baseResult - The result from the base feature check logic
     * @returns The final feature enablement result (true or false)
     */
    check(keys: string[], context: AXPSessionContext, baseResult: boolean): boolean;
}

/**
 * Optional injection token for feature checker.
 * If provided, the checker will be called to potentially override
 * feature enablement results based on custom logic.
 */
declare const AXP_FEATURE_CHECKER: InjectionToken<AXPFeatureChecker>;

declare class AXPSessionService {
    private eventService;
    private authStrategyRegistry;
    private readonly injector;
    static readonly SESSION_KEY = "AXP_SESSION";
    private readonly permissionLoader;
    private readonly featureLoader;
    private readonly tenantLoader;
    private readonly applicationLoader;
    private readonly permissionChecker;
    private readonly featureChecker;
    private status;
    readonly status$: Observable<AXPSessionStatus>;
    private isLoading;
    readonly isLoading$: Observable<boolean>;
    private currentUserSubject;
    readonly user$: Observable<AXPUser | null>;
    get user(): AXPUser | null;
    private currentTenantSubject;
    readonly tenant$: Observable<AXPTenant | null>;
    get tenant(): AXPTenant | null;
    get tenants$(): Observable<AXPTenant[]>;
    private currentApplicationSubject;
    readonly application$: Observable<AXPApplication | null>;
    get application(): AXPApplication | null;
    get applications$(): Observable<AXPApplication[]>;
    private permissionsSubject;
    readonly permissions$: Observable<never[] | string[]>;
    get permissions(): AXPPermission[];
    private featuresSubject;
    readonly features$: Observable<never[] | AXPFeature[]>;
    get features(): AXPFeature[];
    readonly isAuthenticated$: Observable<boolean>;
    readonly isAuthenticatedWithLoading$: Observable<boolean>;
    readonly isAuthorized$: Observable<boolean>;
    restoreSession(): Promise<void>;
    signin(credentials: AXPBaseCredentials): Promise<void>;
    updateToken(params?: {
        [key: string]: any;
    }): Promise<void>;
    signout(): Promise<void>;
    refreshToken(): Promise<any>;
    private loadPermissions;
    private loadFeatures;
    signInComplete(): Promise<void>;
    setSession(tokens: Partial<AXPSessionData>): void;
    setStrategy(strategy: string): void;
    getSessionData(): AXPSessionData | null;
    private clearSession;
    authorize(...keys: string[]): boolean;
    isFeatureEnabled(...keys: string[]): boolean;
    /**
     * Checks if a module is enabled for the current tenant/application.
     * Module names are stored as features with value: true when enabled.
     * Module names can be provided in PascalCase (e.g., 'SecurityManagement') or kebab-case (e.g., 'security-management').
     */
    isModuleEnabled(moduleName: string): boolean;
    getToken(): string | undefined;
    getContext(): AXPSessionContext;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPSessionService, never>;
    static ɵprov: i0.ɵɵInjectableDeclaration<AXPSessionService>;
}

declare class AXPPermissionEvaluatorScopeProvider implements AXPExpressionEvaluatorScopeProvider {
    protected sessionService: AXPSessionService;
    provide(context: AXPExpressionEvaluatorScopeProviderContext): Promise<void>;
}

/**
 * Interface for permission checkers that can override authorization results.
 * Checkers receive the permission keys, current context, and base result,
 * and can return a modified result based on custom logic.
 */
interface AXPPermissionChecker {
    /**
     * Checks and potentially overrides the authorization result.
     * @param keys - The permission keys being checked
     * @param context - Current session context (user, tenant, application)
     * @param baseResult - The result from the base authorization logic
     * @returns The final authorization result (true or false)
     */
    check(keys: string[], context: AXPSessionContext, baseResult: boolean): boolean;
}

/**
 * Optional injection token for permission checker.
 * If provided, the checker will be called to potentially override
 * authorization results based on custom logic.
 */
declare const AXP_PERMISSION_CHECKER: InjectionToken<AXPPermissionChecker>;

declare const AXPAuthGuard: CanActivateFn;

interface AXPAuthModuleConfigs {
    strategies: (new () => AXPAuthStrategy)[];
}
declare function initializeAppState(service: AXPSessionService): () => Promise<void>;
declare class AXPAuthModule {
    static forRoot(configs?: AXPAuthModuleConfigs): ModuleWithProviders<AXPAuthModule>;
    static forChild(configs?: AXPAuthModuleConfigs): ModuleWithProviders<AXPAuthModule>;
    /**
     * @ignore
     */
    constructor(instances: any[]);
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPAuthModule, [{ optional: true; }]>;
    static ɵmod: i0.ɵɵNgModuleDeclaration<AXPAuthModule, [typeof AXPPermissionDirective, typeof AXPFeatureDirective], never, [typeof AXPPermissionDirective, typeof AXPFeatureDirective]>;
    static ɵinj: i0.ɵɵInjectorDeclaration<AXPAuthModule>;
}

declare class AXPAuthStrategyRegistryService {
    private strategies;
    private injector;
    constructor(injector: Injector);
    register(...plugins: (new () => AXPAuthStrategy)[]): void;
    get(strategyKey: string): AXPAuthStrategy | undefined;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPAuthStrategyRegistryService, never>;
    static ɵprov: i0.ɵɵInjectableDeclaration<AXPAuthStrategyRegistryService>;
}

/**
 * Utility class for JWT token operations
 */
declare class JwtUtil {
    /**
     * Parses a JWT token and returns the payload
     */
    static parseJwt(token: string): any;
}
/**
 * Utility class for PKCE (Proof Key for Code Exchange) operations
 */
declare class PkceUtil {
    /**
     * Generates a random string for PKCE code verifier
     */
    static generateRandomString(length: number): string;
    /**
     * Generates PKCE code challenge from verifier
     */
    static generateCodeChallenge(codeVerifier: string): Promise<string>;
    /**
     * Base64 URL encoding for PKCE
     */
    private static base64UrlEncode;
}
/**
 * Utility class for time and date operations
 */
declare class TimeUtil {
    /**
     * Calculates the time difference in milliseconds between a future date and now
     */
    static expiresInMilliseconds(expiresInDate: string): number;
    /**
     * Calculates expiration date from seconds
     */
    static calculateExpireInDate(expireInSeconds: number): string;
}

declare class AXPUnauthorizedError extends Error {
    data?: {
        redirectUrl?: string;
    } | undefined;
    constructor(message?: string, data?: {
        redirectUrl?: string;
    } | undefined);
}
declare class AXPUnauthenticatedError extends Error {
    data?: {
        redirectUrl?: string;
    } | undefined;
    constructor(message?: string, data?: {
        redirectUrl?: string;
    } | undefined);
}

/**
 * Supported content types for challenge display
 */
type AXPChallengeContentType = 'image-url' | 'image-base64' | 'text' | 'audio-url';
/**
 * Challenge data returned from the server
 * Contains all information needed to display and submit a challenge
 */
interface AXPLoginChallengeData {
    /**
     * Unique identifier for this challenge
     * Must be sent back with credentials when submitting login
     */
    id: string;
    /**
     * The challenge content to display
     * Could be an image URL, base64 encoded image, text, or audio URL
     */
    content: string;
    /**
     * Type of content for proper rendering
     */
    contentType: AXPChallengeContentType;
    /**
     * When this challenge expires (optional)
     * After expiration, a new challenge should be fetched
     */
    expiresAt?: Date;
    /**
     * Additional metadata from server (optional)
     */
    metadata?: Record<string, unknown>;
}
/**
 * Result of checking a login error response
 * Determines if a challenge should be displayed
 */
interface AXPChallengeCheckResult {
    /**
     * Whether a challenge is required
     */
    required: boolean;
    /**
     * Optional message to display to the user
     */
    message?: string;
    /**
     * Additional data from server that may be needed for getChallenge()
     * For example: sessionId, attemptId, etc.
     */
    serverData?: Record<string, unknown>;
}

/**
 * Base class for login challenge UI components
 *
 * Providers can extend this class to create custom challenge UIs.
 * The login component will render this component and listen to its outputs.
 *
 * @example
 * ```typescript
 * @Component({
 *   selector: 'my-captcha-challenge',
 *   template: `
 *     <div class="captcha-container">
 *       <img [src]="'data:image/png;base64,' + challengeData().content" />
 *       <input
 *         type="text"
 *         [value]="response()"
 *         (input)="onResponseChange($event)"
 *       />
 *       <button (click)="onRefreshClick()">Refresh</button>
 *     </div>
 *   `
 * })
 * export class MyCaptchaChallengeComponent extends AXPLoginChallengeComponentBase {
 *   response = signal('');
 *
 *   onResponseChange(event: Event) {
 *     const value = (event.target as HTMLInputElement).value;
 *     this.response.set(value);
 *     this.responseChange.emit(value);
 *   }
 *
 *   onRefreshClick() {
 *     this.refreshRequest.emit();
 *   }
 * }
 * ```
 */
declare abstract class AXPLoginChallengeComponentBase {
    /**
     * Challenge data to display
     * Contains the image/content and metadata from the server
     */
    challengeData: i0.InputSignal<AXPLoginChallengeData>;
    /**
     * Whether the challenge is currently loading (e.g., refreshing)
     */
    isLoading: i0.InputSignal<boolean>;
    /**
     * Emits when the user enters or changes their response
     * The login component will capture this value and include it in credentials
     */
    responseChange: i0.OutputEmitterRef<string>;
    /**
     * Emits when the user requests a new challenge (e.g., clicks refresh button)
     * The login component will call provider.refreshChallenge()
     */
    refreshRequest: i0.OutputEmitterRef<void>;
    static ɵfac: i0.ɵɵFactoryDeclaration<AXPLoginChallengeComponentBase, never>;
    static ɵcmp: i0.ɵɵComponentDeclaration<AXPLoginChallengeComponentBase, "ng-component", never, { "challengeData": { "alias": "challengeData"; "required": true; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": false; "isSignal": true; }; }, { "responseChange": "responseChange"; "refreshRequest": "refreshRequest"; }, never, never, true, never>;
}

/**
 * Abstract base class for login challenge providers
 *
 * Implement this class to create custom challenge mechanisms like:
 * - Image CAPTCHA
 * - reCAPTCHA
 * - SMS verification
 * - Email verification
 *
 * @example
 * ```typescript
 * @Injectable()
 * export class MyImageCaptchaProvider extends AXPLoginChallengeProvider {
 *   readonly name = 'image-captcha';
 *
 *   checkResponse(error: unknown): AXPChallengeCheckResult | null {
 *     if (error instanceof HttpErrorResponse) {
 *       if (error.error?.requiresCaptcha) {
 *         return { required: true };
 *       }
 *     }
 *     return null;
 *   }
 *
 *   async getChallenge(): Promise<AXPLoginChallengeData> {
 *     const response = await this.http.get('/api/captcha').toPromise();
 *     return {
 *       id: response.id,
 *       content: response.image,
 *       contentType: 'image-base64'
 *     };
 *   }
 *
 *   async refreshChallenge(): Promise<AXPLoginChallengeData> {
 *     return this.getChallenge();
 *   }
 *
 *   getChallengeComponent(): Type<AXPLoginChallengeComponentBase> {
 *     return MyCaptchaChallengeComponent;
 *   }
 * }
 * ```
 */
declare abstract class AXPLoginChallengeProvider {
    /**
     * Unique name identifier for this provider
     */
    abstract readonly name: string;
    /**
     * Checks the login error response to determine if a challenge is required
     *
     * This method is called after a failed login attempt. The implementation
     * should inspect the error and return a result indicating whether a
     * challenge should be displayed.
     *
     * @param error - The error from the failed login attempt (type varies by implementation)
     * @returns Challenge check result, or null if this provider doesn't handle this error
     */
    abstract checkResponse(error: unknown): AXPChallengeCheckResult | null;
    /**
     * Fetches a new challenge from the server
     *
     * Called when checkResponse indicates a challenge is required.
     * Should make an API call to get challenge data (e.g., CAPTCHA image).
     *
     * @param serverData - Optional data from checkResponse result that may be needed
     * @returns Promise resolving to challenge data for display
     */
    abstract getChallenge(serverData?: Record<string, unknown>): Promise<AXPLoginChallengeData>;
    /**
     * Fetches a fresh challenge, replacing the current one
     *
     * Called when user requests a new challenge (e.g., clicks "new image" button).
     * Typically delegates to getChallenge() but may have different behavior.
     *
     * @returns Promise resolving to new challenge data
     */
    abstract refreshChallenge(): Promise<AXPLoginChallengeData>;
    /**
     * Returns the component type for rendering the challenge UI
     *
     * Override this method to provide a custom challenge UI component.
     * If not overridden (returns null), the login component will use
     * a default built-in UI.
     *
     * @returns Component type extending AXPLoginChallengeComponentBase, or null for default UI
     */
    getChallengeComponent(): Type<AXPLoginChallengeComponentBase> | null;
}

/**
 * Injection token for the login challenge provider
 *
 * This token is optional - if not provided, no challenge mechanism will be used.
 *
 * @example
 * ```typescript
 * // In your app module or provider configuration:
 * providers: [
 *   {
 *     provide: AXP_LOGIN_CHALLENGE_PROVIDER,
 *     useClass: MyImageCaptchaProvider
 *   }
 * ]
 *
 * // In a component:
 * private challengeProvider = inject(AXP_LOGIN_CHALLENGE_PROVIDER, { optional: true });
 * ```
 */
declare const AXP_LOGIN_CHALLENGE_PROVIDER: InjectionToken<AXPLoginChallengeProvider>;

export { AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureGuard, AXPLoginChallengeComponentBase, AXPLoginChallengeProvider, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPUnauthenticatedError, AXPUnauthorizedError, AXP_APPLICATION_LOADER, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_LOGIN_CHALLENGE_PROVIDER, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_TENANT_LOADER, JwtUtil, PkceUtil, TimeUtil, initializeAppState };
export type { AXPApplication, AXPApplicationLoader, AXPAuthModuleConfigs, AXPBaseCredentials, AXPChallengeCheckResult, AXPChallengeContentType, AXPEdition, AXPFeature, AXPFeatureChecker, AXPFeatureLoader, AXPLoginChallengeData, AXPPermission, AXPPermissionChecker, AXPPermissionDefinition, AXPPermissionDefinitionProvider, AXPPermissionGroupDefinition, AXPPermissionLoader, AXPSessionData, AXPSignInResult, AXPTenant, AXPTenantLoader, AXPTokenResult, AXPUser };
