/**
 * Hypen App Builder API
 * Implements the stateful module system from RFC-0001
 */
import type { Action } from "./types.js";
import type { Session } from "./remote/types.js";
import { HypenError } from "./result.js";
import { type DataSourcePlugin } from "./datasource.js";
export interface IEngine {
    setModule(name: string, actions: string[], stateKeys: string[], initialState: unknown): void;
    onAction(actionName: string, handler: (action: Action) => void | Promise<void>): void;
    notifyStateChange(paths: string[], changedValues: Record<string, unknown>): void;
}
import type { HypenRouter } from "./router.js";
import type { HypenGlobalContext, ModuleReference } from "./context.js";
export type ActionContext<P = unknown> = {
    name: string;
    payload?: P;
    sender?: string;
};
export type GlobalContext = {
    getModule: <T = unknown>(id: string) => ModuleReference<T>;
    hasModule: (id: string) => boolean;
    getModuleIds: () => string[];
    getGlobalState: () => Record<string, unknown>;
    emit: (event: string, payload?: unknown) => void;
    on: (event: string, handler: (payload?: unknown) => void) => () => void;
    router: HypenRouter | null;
};
export type LifecycleHandler<T> = (state: T, context?: GlobalContext) => void | Promise<void>;
/**
 * Action handler context - all parameters available explicitly
 */
export interface ActionHandlerContext<T, P = unknown> {
    action: ActionContext<P>;
    state: T;
    context: GlobalContext;
    /** Access to registered data source plugins for mutations */
    dataSources: DataSourceAccessor;
}
/**
 * Provides typed access to registered data source plugins.
 * Unknown method calls are forwarded to `plugin.call()`:
 *   `dataSources.spacetime.sendMessage(text)` → `plugin.call("sendMessage", text)`
 *
 * You can also call `.call()` directly if you prefer:
 *   `dataSources.spacetime.call("sendMessage", text)`
 */
export interface DataSourceAccessor {
    [providerName: string]: DataSourcePlugin & Record<string, (...args: unknown[]) => Promise<unknown>>;
}
/**
 * Action handler - receives all context in a single object
 */
export type ActionHandler<T, P = unknown> = (ctx: ActionHandlerContext<T, P>) => void | Promise<void>;
/**
 * Context passed to onDisconnect handler
 */
export interface DisconnectContext<T> {
    /** Current state snapshot (ready to serialize and save) */
    state: T;
    /** Session information */
    session: Session;
}
/**
 * Context passed to onReconnect handler
 */
export interface ReconnectContext<T> {
    /** Session information */
    session: Session;
    /** Call this with saved state to restore it */
    restore: (savedState: T) => void;
}
/**
 * Context passed to onExpire handler
 */
export interface ExpireContext {
    /** Session information */
    session: Session;
}
/**
 * Handler called when client disconnects (session still alive for TTL)
 */
export type DisconnectHandler<T> = (ctx: DisconnectContext<T>) => void | Promise<void>;
/**
 * Handler called when client reconnects with existing session
 */
export type ReconnectHandler<T> = (ctx: ReconnectContext<T>) => void | Promise<void>;
/**
 * Handler called when session TTL expires (client never reconnected)
 */
export type ExpireHandler = (ctx: ExpireContext) => void | Promise<void>;
/**
 * Context passed to onError handler
 */
export interface ErrorContext<T> {
    /** The error that occurred */
    error: HypenError;
    /** Current state (for inspection, not mutation during error handling) */
    state: T;
    /** The action name if error occurred in an action handler */
    actionName?: string;
    /** The lifecycle phase if error occurred in a lifecycle handler */
    lifecycle?: "created" | "destroyed" | "disconnect" | "reconnect" | "expire";
}
/**
 * Error handler return type - controls error propagation
 */
export type ErrorHandlerResult = void | {
    handled: true;
} | {
    retry: true;
} | {
    rethrow: true;
};
/**
 * Handler called when an error occurs in the module
 */
export type ErrorHandler<T> = (ctx: ErrorContext<T>) => ErrorHandlerResult | Promise<ErrorHandlerResult>;
export interface HypenModuleDefinition<T = unknown> {
    name?: string;
    actions: string[];
    stateKeys: string[];
    persist?: boolean;
    version?: number;
    initialState: T;
    /**
     * Inline UI template for single-file components.
     * Set via the `.ui(hypen`...`)` method.
     */
    template?: string;
    /**
     * Data source plugins registered via `.useDataSource()`.
     * Each entry contains the plugin and its configuration.
     */
    dataSources?: Array<{
        plugin: DataSourcePlugin;
        config: unknown;
    }>;
    handlers: {
        onCreated?: LifecycleHandler<T>;
        onAction: Map<string, ActionHandler<T, any>>;
        onDestroyed?: LifecycleHandler<T>;
        /** Called when client disconnects (session persists for TTL) */
        onDisconnect?: DisconnectHandler<T>;
        /** Called when client reconnects with existing session */
        onReconnect?: ReconnectHandler<T>;
        /** Called when session TTL expires */
        onExpire?: ExpireHandler;
        /** Called when any error occurs in the module */
        onError?: ErrorHandler<T>;
    };
}
/**
 * Alias for HypenModuleDefinition for backward compatibility
 */
export type HypenModule<T = unknown> = HypenModuleDefinition<T>;
/**
 * Builder for creating Hypen app modules
 */
export declare class HypenAppBuilder<T> {
    private initialState;
    private options;
    private createdHandler?;
    private actionHandlers;
    private destroyedHandler?;
    private disconnectHandler?;
    private reconnectHandler?;
    private expireHandler?;
    private errorHandler?;
    private template?;
    private _registry?;
    private dataSourceEntries;
    constructor(initialState: T, options?: {
        persist?: boolean;
        version?: number;
        name?: string;
    }, registry?: Map<string, HypenModuleDefinition>);
    /**
     * Register a handler for module creation
     */
    onCreated(fn: LifecycleHandler<T>): this;
    /**
     * Register a handler for a specific action.
     * Optionally provide a payload type parameter for typed action payloads.
     *
     * @example
     * ```typescript
     * // Typed payload:
     * .onAction<{ amount: number }>("add", ({ action, state }) => {
     *   action.payload.amount; // fully typed
     * })
     *
     * // Untyped (payload is unknown):
     * .onAction("add", ({ action, state }) => {
     *   action.payload; // unknown
     * })
     * ```
     */
    onAction<P = unknown>(name: string, fn: ActionHandler<T, P>): this;
    /**
     * Register a handler for module destruction
     */
    onDestroyed(fn: LifecycleHandler<T>): this;
    /**
     * Register a handler for client disconnection
     * Called when client disconnects; session persists for TTL
     * Use this to save state for later restoration
     */
    onDisconnect(fn: DisconnectHandler<T>): this;
    /**
     * Register a handler for session reconnection
     * Called when client reconnects with an existing session ID
     * Use restore() to hydrate state from saved data
     */
    onReconnect(fn: ReconnectHandler<T>): this;
    /**
     * Register a handler for session expiration
     * Called when TTL expires and client never reconnected
     * Use this to clean up stored state
     */
    onExpire(fn: ExpireHandler): this;
    /**
     * Register an error handler for the module
     * Called when any error occurs in action handlers or lifecycle hooks
     *
     * @example
     * ```typescript
     * app
     *   .defineState({ count: 0 })
     *   .onAction("increment", ({ state }) => {
     *     if (state.count > 100) throw new Error("Count too high");
     *     state.count += 1;
     *   })
     *   .onError(({ error, actionName, state }) => {
     *     console.error(`Error in ${actionName}:`, error.message);
     *     // Optionally recover
     *     if (error.message.includes("too high")) {
     *       return { handled: true }; // Don't propagate
     *     }
     *     // Or retry
     *     // return { retry: true };
     *   })
     *   .build();
     * ```
     *
     * @param fn - Error handler function
     * @returns Builder for chaining
     */
    onError(fn: ErrorHandler<T>): this;
    /**
     * Register a data source plugin for live database subscriptions.
     *
     * @example
     * ```typescript
     * import { SpacetimeDBPlugin } from "@hypen-space/plugin-spacetimedb";
     *
     * export default app
     *   .defineState({ messageText: "" })
     *   .useDataSource(new SpacetimeDBPlugin(), {
     *     uri: "ws://localhost:3000",
     *     moduleName: "chat",
     *     tables: ["user", "message"],
     *   })
     *   .onAction("sendMessage", async ({ state, dataSources }) => {
     *     await dataSources.spacetime.sendMessage(state.messageText);
     *     state.messageText = "";
     *   })
     *   .build();
     * ```
     *
     * In Hypen DSL, bind to data source tables with `$provider.table`:
     * ```hypen
     * ForEach(items: $spacetime.message, key: "id") {
     *   Text("${item.text}")
     * }
     * ```
     */
    useDataSource<C>(plugin: DataSourcePlugin<C>, config: C): this;
    /**
     * Define the component's UI template inline (single-file component).
     *
     * Use with the `hypen` tagged template literal and binding proxies:
     *
     * @example
     * ```typescript
     * import { app, hypen, state } from "@hypen-space/core";
     *
     * export default app
     *   .defineState({ count: 0 })
     *   .onAction("increment", ({ state }) => {
     *     state.count += 1;
     *   })
     *   .ui(hypen`
     *     Column {
     *       Text("Count: ${state.count}")
     *       Button { Text("+") }
     *         .onClick("@actions.increment")
     *     }
     *   `);
     * ```
     *
     * @param template - The Hypen DSL template string
     * @returns The built module definition (calls build() internally)
     */
    ui(template: string): HypenModuleDefinition<T>;
    /**
     * Load a UI template from a .hypen file on disk.
     *
     * @example
     * ```typescript
     * import { app } from "@hypen-space/core";
     *
     * export default app
     *   .defineState({ count: 0 })
     *   .onAction("increment", ({ state }) => { state.count += 1; })
     *   .uiFile("./counter.hypen");
     * ```
     *
     * @param path - Path to a .hypen template file
     * @returns The built module definition (calls build() internally)
     */
    uiFile(path: string): HypenModuleDefinition<T>;
    /**
     * Build the module definition
     */
    build(): HypenModuleDefinition<T>;
}
/**
 * Hypen App API — singleton factory and component registry.
 *
 * Modules built with a `name` are automatically registered here.
 * Consumers (ManagedRouter, RemoteServer, ComponentResolver) read from this
 * registry instead of requiring a separate ModuleRegistry instance.
 */
export declare class HypenApp {
    /** @internal */
    readonly _registry: Map<string, HypenModuleDefinition<unknown>>;
    /**
     * Define the initial state for a module
     */
    defineState<T>(initial: T, options?: {
        persist?: boolean;
        version?: number;
        name?: string;
    }): HypenAppBuilder<T>;
    /**
     * Convenience: start a module builder with a name pre-set.
     *
     * @example
     * ```typescript
     * export default app
     *   .module("Settings")
     *   .defineState({ theme: "dark" })
     *   .ui(hypen`...`);
     * ```
     */
    module(name: string): {
        defineState: <T>(initial: T, options?: {
            persist?: boolean;
            version?: number;
        }) => HypenAppBuilder<T>;
    };
    /**
     * Get a registered module definition by component name.
     */
    get(name: string): HypenModuleDefinition | undefined;
    /**
     * Check if a module definition is registered.
     */
    has(name: string): boolean;
    /**
     * Read-only view of all registered component definitions.
     */
    get components(): ReadonlyMap<string, HypenModuleDefinition>;
    /**
     * Get all registered component names.
     */
    getNames(): string[];
    /**
     * Number of registered definitions.
     */
    get size(): number;
    /**
     * Unregister a module definition.
     */
    unregister(name: string): void;
    /**
     * Clear all registered definitions.
     */
    clear(): void;
}
/**
 * The main app instance for creating modules
 */
export declare const app: HypenApp;
/**
 * Module Instance - manages a running module with typed state
 */
export declare class HypenModuleInstance<T extends object = any> {
    private engine;
    private definition;
    private state;
    private isDestroyed;
    private router;
    private globalContext?;
    private stateChangeCallbacks;
    private dataSourceManager?;
    private dataSourceAccessor;
    constructor(engine: IEngine, definition: HypenModuleDefinition<T>, router?: HypenRouter | null, globalContext?: HypenGlobalContext);
    /**
     * Create the global context API for this module
     */
    private createGlobalContextAPI;
    /**
     * Execute an action handler with Result-based error handling
     * Handles both synchronous throws and async rejections
     */
    private executeAction;
    /**
     * Handle an error with module-level error handler support
     * Falls back to default behavior (emit + log) if no handler or handler doesn't suppress
     * @returns true if the error should be rethrown
     */
    private handleError;
    /**
     * Call the onCreated handler and connect data source plugins
     */
    private callCreatedHandler;
    /**
     * Register a callback to be notified when state changes
     */
    onStateChange(callback: () => void): void;
    /**
     * Destroy the module instance and disconnect all data source plugins
     */
    destroy(): Promise<void>;
    /**
     * Get the current state (returns a snapshot)
     */
    getState(): T;
    /**
     * Get the live observable state
     */
    getLiveState(): T;
    /**
     * Update state directly (merges with existing state)
     */
    updateState(patch: Partial<T>): void;
}
