import { IDisposable, ICustomElementViewModel, TaskQueue, IEventAggregator, Controller, IContainer, IPlatform } from 'aurelia';
import { I18N } from '@aurelia/i18n';
import { IAntiBounceSupport, IAntiBounce } from '@aegenet/belt-anti-bounce';
import * as _aurelia_kernel from '@aurelia/kernel';
import { IContainer as IContainer$1, IResolver } from '@aurelia/kernel';
import { IHydratedController } from '@aurelia/runtime-html';
import { IRouteableComponent, Parameters, RoutingInstruction, Navigation, IRouter } from '@aurelia/router';

interface ICustomElementAware {
    eventName?: string;
    $awareToken?: IDisposable;
}

/**
 * Base component, with basic logic
 */
interface IBaseComponent<EBD = unknown> extends ICustomElementViewModel, IAntiBounceSupport, ICustomElementAware {
    /** Token of Aware Component */
    $awareToken?: IDisposable;
    /**
     * Instances of anti-bounce
     * @remark Don't edit manually
     *
     * @private
     * @core
     */
    $antiBounces?: Map<string, IAntiBounce>;
    /**
     * i18n
     * @service
     * @core
     */
    readonly i18n: I18N;
    /**
     * Component ID
     * @core
     */
    readonly uid?: string;
    /**
     * Specify a special name for this instance
     *
     * "Je suis spécial !"
     */
    eventName?: string;
    /**
     * Have u met T... Slots? (slot)
     * @remark We fill this object with slot only (not au-slot)
     * @core
     */
    slots: Record<string, Element>;
    /**
     * Have u met T... AuSlots? (au-slot)
     * @remark We fill this object with au-slot only (just the name)
     * @core
     */
    auSlots: Record<string, boolean>;
    /**
     * Array of au-slot names
     * @core
     */
    auSlotNames?: string[];
    /**
     * Array of slot names
     * @core
     */
    slotNames: string[];
    /**
     * Last error message
     * @core
     */
    lastError?: string;
    /**
     * Is busy ?
     * @core
     */
    isBusy?: boolean;
    /** Embed data */
    embedData?: EBD;
    /**
     * This predicate is called when the value of the bindable (value) property changes.
     *
     * @type callback
     * @input newValue
     * @input oldValue
     * @input embedData
     */
    changed?: (...args: unknown[]) => void;
    /**
     * TaskQueue
     * @remark Can be used to rugged SSR
     * @core
     */
    get taskQueue(): TaskQueue;
    /**
     * Event aggregator
     * @service
     * @core
     */
    get ea(): IEventAggregator;
}

interface IAwareEvent<T = unknown> {
    property: string;
    value: T;
}

declare const DIAwareComponentService: _aurelia_kernel.InterfaceSymbol<IAwareComponentService>;
interface IAwareComponentService {
    /** Subscribe */
    subscribe(customElement: ICustomElementAware & {
        $controller?: Controller;
    }): void;
    /** Publish */
    publish(customElement: ICustomElementAware, options: IAwareEvent): void;
    /** Unsuscribe */
    unsubscribe(customElement: ICustomElementAware): void;
}

/** Common messenger interface */
interface IStoreMessenger {
    /**
     * Subscribes to a message channel.
     *
     * @param channel - The event channel.
     * @param callback - The callback to be invoked when the specified message is published.
     */
    subscribe<T, C extends string>(channel: C, callback: (message: T, channel: C) => void): IDisposable;
    /**
     * Publishes a message.
     *
     * @param channel - The channel to publish to.
     * @param message - The message to publish on the channel.
     */
    publish<T, C extends string>(channel: C, message: T): unknown;
    /** Get single subscriber result for the channel */
    getSingle?<T, C extends string, O = unknown>(channel: C, message: T): Promise<O | undefined>;
    /** Get all subscribers results for the channel */
    getAll?<T, C extends string, O = unknown>(channel: C, message: T): Promise<O[] | undefined>;
}

declare const DIStoreService: _aurelia_kernel.InterfaceSymbol<IStoreService>;
type StoreKey = string | symbol;
type StoreLoadOptions = {
    key: string;
    data?: unknown;
    load?: (container: IContainer) => Promise<unknown>;
};
/**
 * StoreService
 */
interface IStoreService {
    /** Initialize */
    initialize(options?: {
        /** Own event aggregator implementation */
        eventAggregator?: IStoreMessenger;
        /** @default 'au2.store-service' */
        channel?: string;
    }): void;
    /** Dispose */
    dispose(): void;
    /** Set data/load on Store */
    setStore(...options: StoreLoadOptions[]): void;
    /** Delete data/load from Store */
    delStore(key: StoreKey): void;
    /** Get data from Store */
    getStore<T = unknown>(key: StoreKey): Promise<T>;
    /** Refresh data from Store */
    refreshStore(key: StoreKey): Promise<void>;
}

/**
 * Base component, with basic logic
 */
declare class BaseComponent<EBD = unknown> implements IBaseComponent {
    protected _element: Element;
    protected _container: IContainer;
    private static _COUNTER;
    /**
     * Instances of anti-bounce
     * @remark Don't edit manually
     *
     * @private
     * @core
     */
    $antiBounces?: Map<string, IAntiBounce>;
    /**
     * AU Slot informations
     * @core
     */
    private readonly _auSlotInfo;
    /**
     * Event aggregator
     * @service
     * @core
     */
    protected readonly _ea: IEventAggregator;
    /**
     * Aware Service
     * @service
     * @core
     */
    protected readonly _aware: IAwareComponentService;
    /**
     * Platform
     * @service
     * @core
     */
    protected readonly _platform: IPlatform;
    /**
     * StoreService
     * @service
     * @core
     */
    protected readonly _store: IStoreService;
    /**
     * i18n
     * @service
     * @core
     */
    readonly i18n: I18N;
    /**
     * Component ID
     * @core
     */
    readonly uid?: string;
    /**
     * Specify a special name for this instance
     *
     * "Je suis spécial !"
     */
    eventName?: string;
    /**
     * Has been init? (attached & _init())
     * @core
     */
    protected _isInit?: boolean;
    /**
     * Have u met T... Slots? (slot)
     * @remark We fill this object with slot only (not au-slot)
     * @core
     */
    slots: Record<string, Element>;
    /**
     * Have u met T... AuSlots? (au-slot)
     * @remark We fill this object with au-slot only (just the name)
     * @core
     */
    auSlots: Record<string, boolean>;
    /**
     * Array of au-slot names
     * @core
     */
    auSlotNames?: string[];
    /**
     * Array of slot names
     * @core
     */
    slotNames: string[];
    /**
     * Last error message
     * @core
     */
    lastError?: string;
    /**
     * Is busy ?
     * @core
     */
    isBusy?: boolean;
    /** Embed data */
    embedData?: EBD;
    /**
     * This predicate is called when the value of the bindable (value) property changes.
     *
     * @type callback
     * @input newValue
     * @input oldValue
     * @input embedData
     */
    changed?: (...args: unknown[]) => void;
    constructor(_element: Element, _container: IContainer);
    /**
     * On attached we refresh slots and au-slots objects, subscribe to aware service,
     * then we call the protected `_init()` method
     */
    attached(): Promise<void>;
    /**
     * Detaching
     */
    detaching(initiator: IHydratedController, parent: IHydratedController): void;
    /**
     * Custom logic (after attached)
     */
    protected _init(): void | Promise<void>;
    /** Custom logic (after detaching and unbinding, before dispose) */
    protected _deinit(): void | Promise<void>;
    /**
     * Refresh slots and au-slots
     */
    private _refreshSlots;
    /**
     * Unbinding
     */
    unbinding(): Promise<void>;
    /**
     * TaskQueue
     * @remark Can be used to rugged SSR
     * @core
     */
    get taskQueue(): TaskQueue;
    /**
     * Event aggregator
     * @service
     * @core
     */
    get ea(): IEventAggregator;
}

/**
 * Base Page
 */
interface IBasePage extends IRouteableComponent, IAntiBounceSupport, ICustomElementAware {
    /** Token of Aware Component */
    $awareToken?: IDisposable;
    /**
     * Instances of anti-bounce
     * @remark Don't edit manually
     *
     * @private
     * @core
     */
    $antiBounces?: Map<string, IAntiBounce>;
    /**
     * i18n
     * @service
     * @core
     */
    readonly i18n: I18N;
    /**
     * Last error message
     * @core
     */
    lastError?: string;
    loading?(parameters: Parameters, instruction: RoutingInstruction, navigation: Navigation): Promise<void>;
    /** Unload the page */
    unloading(instruction: RoutingInstruction, navigation: Navigation | null): Promise<void>;
    /**
     * TaskQueue
     * @remark Can be used to rugged SSR
     * @core
     */
    get taskQueue(): TaskQueue;
    /**
     * Event aggregator
     * @service
     * @core
     */
    get ea(): IEventAggregator;
}

/**
 * Base Page
 */
declare abstract class BasePage implements IBasePage {
    protected readonly _container: IContainer;
    /**
     * Instances of anti-bounce
     * @remark Don't edit manually
     *
     * @private
     * @core
     */
    $antiBounces?: Map<string, IAntiBounce>;
    /**
     * Event aggregator
     * @service
     * @core
     */
    protected readonly _ea: IEventAggregator;
    /**
     * Specify a special name for this instance
     *
     * "Je suis spécial !"
     */
    eventName?: string;
    /**
     * Aware Service
     * @service
     * @core
     */
    protected readonly _aware: IAwareComponentService;
    /**
     * StoreService
     * @service
     * @core
     */
    protected _store: IStoreService;
    /**
     * i18n
     * @service
     * @core
     */
    readonly i18n: I18N;
    /** Router */
    protected readonly _router: IRouter;
    /**
     * Platform
     * @service
     * @core
     */
    protected readonly _platform: IPlatform;
    /**
     * Has been init? (attached & _init())
     * @core
     */
    protected _isInit?: boolean;
    /**
     * Last error message
     * @core
     */
    lastError?: string;
    constructor(_container: IContainer);
    loading?(parameters: Parameters, instruction: RoutingInstruction, navigation: Navigation): Promise<void>;
    /**
     * Custom logic (on loading)
     */
    protected _init(parameters: Parameters, instruction: RoutingInstruction, navigation: Navigation): void | Promise<void>;
    /** Custom logic (on unloading) */
    protected _deinit(instruction: RoutingInstruction, navigation: Navigation | null): void | Promise<void>;
    /** Unload the page */
    unloading(instruction: RoutingInstruction, navigation: Navigation | null): Promise<void>;
    /**
     * TaskQueue
     * @remark Can be used to rugged SSR
     * @core
     */
    get taskQueue(): TaskQueue;
    /**
     * Event aggregator
     * @service
     * @core
     */
    get ea(): IEventAggregator;
    /** Router */
    get router(): IRouter;
}

/** Register the plugin */
declare function register(): {
    register: (container: IContainer) => void;
};

declare class AwareComponentService implements IAwareComponentService {
    private readonly _ev;
    private static readonly _RE_PROPERTY_CHECK;
    constructor(_ev: IEventAggregator);
    /**
     * @inheritdoc
     */
    subscribe(customElement: ICustomElementAware & {
        $controller?: Controller;
    }): void;
    /**
     * @inheritdoc
     */
    publish(customElement: ICustomElementAware, options: IAwareEvent): void;
    /**
     * @inheritdoc
     */
    unsubscribe(customElement: ICustomElementAware): void;
}

/**
 * Aware Component Interface
 */
interface IAwareComponent<EBD = unknown> extends BaseComponent<EBD> {
    /**
     * Events
     */
    events: Array<{
        name: string;
        options: IAwareEvent;
    }>;
    /** Next */
    next?: (source: IAwareComponent) => void | Promise<void>;
    /** Publish the event */
    publish(): Promise<void>;
}

/**
 * Aware Component
 *
 * @category components/events
 *
 * @story Simple
 * ```html
 * <let is-checked.bind="false"></let>
 * <let next-has-been-called.bind="false"></let>
 *
 * <ra-checkbox event-name="my-box" value.bind="isChecked"></ra-checkbox>
 *
 * <aware-component component.ref="awareEvRef"
 *    events.bind="[{ name: 'ra-checkbox:my-box', options: { property: 'value', value: !isChecked } }]"
 *    next.bind="() => nextHasBeenCalled = true"
 * >
 * </aware-component>
 *
 * <button
 *    click.trigger"awareEvRef.publish()"
 * >
 *      Toggled via event
 * </button>
 *
 * <div class="m-5">Result: <strong>${isChecked}</strong> (next called: ${nextHasBeenCalled})</div>
 * ```
 */
declare class AwareComponent<EBD = unknown> extends BaseComponent<EBD> implements IAwareComponent<EBD> {
    /**
     * Events
     */
    events: Array<{
        name: string;
        options: IAwareEvent;
    }>;
    /** Next */
    next?: (source: AwareComponent) => void | Promise<void>;
    constructor(element: Element, container: IContainer);
    /** Publish the event */
    publish(): Promise<void>;
}

/**
 * StoreService
 */
declare class StoreService implements IStoreService {
    private readonly _container;
    private _isInit;
    private readonly _store;
    private _tokens;
    private _channel;
    private _ev?;
    constructor(_container: IContainer);
    /** Initialize */
    initialize(options?: {
        /** event aggregator implementation */
        eventAggregator?: IStoreMessenger;
        /** @default 'au2.store-service' */
        channel?: string;
    }): void;
    /** Dispose */
    dispose(): void;
    /** Set data/load on Store */
    setStore(...options: StoreLoadOptions[]): void;
    /** Delete data/load from Store */
    delStore(key: StoreKey): void;
    /** Get data from Store */
    getStore<T = unknown>(key: StoreKey): Promise<T>;
    /** Refresh data from Store */
    refreshStore(key: StoreKey): Promise<void>;
}

/**
 * Internal usage
 * https://github.com/aurelia/aurelia/blob/master/packages/kernel/src/di.ts#L777
 */
declare enum ResolverStrategyMap {
    instance = 0,
    singleton = 1,
    transient = 2,
    callback = 3,
    array = 4,
    alias = 5
}
type DebugContainerStats = {
    [K in keyof typeof ResolverStrategyMap]: Record<string, {
        resolving: boolean;
        current: unknown | null;
    }>[];
};
/**
 * Get the container informations
 */
declare function debugContainer(container: (IContainer$1 & {
    h?: Map<any, IResolver & {
        resolving?: boolean;
        _state?: unknown;
        C?: number;
    }>;
    u?: Map<any, any>;
}) | undefined | null): DebugContainerStats;

/**
 * Default capture
 */
declare function defaultCapture(attr: string): boolean;

export { AwareComponent, AwareComponentService, BaseComponent, BasePage, DIAwareComponentService, DIStoreService, type DebugContainerStats, type IAwareComponentService, type IAwareEvent, type IBaseComponent, type IBasePage, type ICustomElementAware, type IStoreMessenger, type IStoreService, ResolverStrategyMap, type StoreKey, type StoreLoadOptions, StoreService, debugContainer, defaultCapture, register };
