import { OnDestroy } from '@angular/core';
import { WorkspaceStateManager, NavItem, ApplicationManager } from '@memberjunction/ng-base-application';
import { NavigationOptions } from './navigation.interfaces';
import { CompositeKey } from '@memberjunction/core';
import { BehaviorSubject, Subject, Observable } from 'rxjs';
import type { AppContextSnapshot } from '@memberjunction/ai-core-plus';
import { BaseResourceComponent } from './base-resource-component';
import * as i0 from "@angular/core";
/**
 * Event emitted when query params change on a tab (e.g., from browser back/forward).
 * Includes the tab ID so that only the component in the affected tab reacts,
 * preventing cross-tab leakage in multi-tab scenarios.
 */
export interface QueryParamChangeEvent {
    TabId: string;
    Params: Record<string, string>;
}
/**
 * Event emitted when a resource component reports its agent context or tools.
 * The shell (which owns the ComponentCacheManager) subscribes to these events
 * and updates the cache + active AppContextSnapshot accordingly.
 */
export interface AgentContextUpdate {
    /** The component instance that reported the update */
    Caller: BaseResourceComponent;
    /** Dashboard-specific context for the agent (undefined = no change) */
    AgentContext?: Record<string, unknown>;
    /** Client tools available from this dashboard (undefined = no change) */
    AgentClientTools?: Array<{
        Name: string;
        Description: string;
        ParameterSchema: Record<string, unknown>;
        Handler: (params: Record<string, unknown>) => Promise<unknown>;
    }>;
}
/**
 * System application ID for non-app-specific resources (fallback only)
 * Uses double underscore prefix to indicate system-level resource
 * @deprecated Prefer using NavigationService.getDefaultApplicationId() instead
 */
export declare const SYSTEM_APP_ID = "__explorer";
/**
 * Centralized navigation service that handles all navigation operations
 * with automatic shift-key detection for power user workflows
 */
export declare class NavigationService implements OnDestroy {
    private workspaceManager;
    private appManager;
    private shiftKeyPressed;
    private subscriptions;
    private queryParamChanged$;
    /** Observable that emits when query params change on a tab (back/forward navigation). */
    QueryParamChanged$: Observable<QueryParamChangeEvent>;
    /** Cached Home app ID (null means not found, undefined means not checked) */
    private _homeAppId;
    /** Cached Home app color */
    private _homeAppColor;
    constructor(workspaceManager: WorkspaceStateManager, appManager: ApplicationManager);
    /**
     * Get the neutral color used for system-wide resources (entities, views, dashboards)
     * Returns a light neutral gray
     * @deprecated Use getDefaultAppColor() for better UX with Home app integration
     */
    get ExplorerAppColor(): string;
    /**
     * Gets the default application ID for orphan resources.
     * Priority: Home app > Active app > SYSTEM_APP_ID
     *
     * This ensures orphan resources (entity records, dashboards, views opened directly)
     * are grouped under the Home app instead of being orphaned in the tab system.
     */
    private getDefaultApplicationId;
    /**
     * Gets the default app color for orphan resources.
     * Returns Home app color if available, otherwise neutral gray.
     */
    private getDefaultAppColor;
    /**
     * Clears the cached Home app info.
     * Call this if apps are reloaded or user logs out.
     */
    clearHomeAppCache(): void;
    /**
     * Observable stream of agent context updates from resource components.
     * The shell subscribes to this to update the ComponentCacheManager and
     * push changes to the chat overlay's AppContextSnapshot.DashboardContext.
     */
    readonly AgentContextUpdated$: Subject<AgentContextUpdate>;
    /**
     * Latest `AppContextSnapshot` published by the Explorer app shell.
     *
     * Why: any embedded `<mj-conversation-chat-area>` instance outside the
     * floating chat overlay (Form Builder cockpit, future domain dashboards
     * that pop their own AI pane) needs to feed the SAME context the overlay
     * does so the agent sees what app + view + dashboard state the user is
     * looking at. Without this, the agent only sees the embedder's narrow
     * `AdditionalContext` slice and treats the user as if they have no app
     * context at all — which is the bug we just fixed.
     *
     * `MJExplorerAppComponent` is the canonical publisher (it owns the
     * snapshot construction); consumers SUBSCRIBE and bind the value to
     * their chat-area's `[appContext]`. Non-Explorer apps (custom MJ apps
     * that don't include explorer-app at all) build their own snapshot via
     * `BuildAppContextSnapshot()` in `@memberjunction/ai-core-plus`.
     *
     * Initial value is `null`; the publisher emits the first real snapshot
     * after the active app + nav state resolve on bootstrap.
     */
    readonly AppContextSnapshot$: BehaviorSubject<AppContextSnapshot | null>;
    /**
     * Push a fresh AppContextSnapshot. Called by MJExplorerAppComponent
     * after each (a) app/tab change, (b) `handleAgentContextUpdate`
     * merging in `AdditionalContext` from a dashboard. Idempotent — no
     * de-duplication; embedders should treat the stream as "the latest
     * value is canonical."
     */
    PublishAppContextSnapshot(snapshot: AppContextSnapshot | null): void;
    /**
     * Report the current agent-visible state from a resource component.
     * Call this whenever the dashboard's internal state changes (tab switch,
     * filter change, pipeline status change, drill-down, etc.).
     *
     * @param caller - Pass `this` from the calling component. Used to match
     *   against the ComponentCacheManager to identify which cached component
     *   this update belongs to.
     * @param context - Key-value pairs representing dashboard state the agent
     *   should know about. Each dashboard defines its own shape.
     */
    SetAgentContext(caller: BaseResourceComponent, context: Record<string, unknown>): void;
    /**
     * Register the client tools available from a resource component.
     * Call this on component init and whenever the available tools change.
     * Tools are automatically unregistered when the component becomes inactive
     * (tab switch) and re-registered when it becomes active again.
     *
     * @param caller - Pass `this` from the calling component.
     * @param tools - Array of tool definitions with Name, Description,
     *   ParameterSchema (JSON Schema), and Handler function.
     */
    SetAgentClientTools(caller: BaseResourceComponent, tools: Array<{
        Name: string;
        Description: string;
        ParameterSchema: Record<string, unknown>;
        Handler: (params: Record<string, unknown>) => Promise<unknown>;
    }>): void;
    ngOnDestroy(): void;
    /**
     * Set up global keyboard event listeners to track shift key state
     */
    private setupGlobalShiftKeyDetection;
    /**
     * Get current shift key state
     */
    private isShiftPressed;
    /**
     * Determine if a new tab should be forced based on options and shift key state
     */
    private shouldForceNewTab;
    /**
     * Returns whether the caller should use OpenTabForced (force-new path) or
     * OpenTab (replace-temp path).
     *
     * Rule: only honor an explicit force-new request — from the user via
     * shift+click, or from the caller via `options.forceNewTab`. We deliberately
     * do NOT apply heuristics that auto-switch the workspace out of
     * single-resource mode on cross-resource navigation. A previous version of
     * this method tried to do that ("force new if single-resource + different
     * resource") and it caused a regression: every plain hyperlink click on a
     * record opened a new tab and dropped the user into multi-tab mode, even
     * though they didn't ask for it. That violated the principle that mode
     * transitions are user-driven (shift) or explicitly requested (options).
     *
     * If a particular caller really needs the parent context preserved when
     * creating/navigating to a child resource (e.g. "+New" on a related-entity
     * grid inside an open record), the caller should pass `forceNewTab: true`
     * in `NavigationOptions`. That keeps intent explicit at the call site
     * instead of buried in a global heuristic.
     */
    private handleSingleResourceModeTransition;
    /**
     * Check if a tab request matches an existing tab's resource
     */
    private isSameResource;
    /**
     * Open a navigation item within an app
     */
    OpenNavItem(appId: string, navItem: NavItem, appColor: string, options?: NavigationOptions): string;
    /**
     * Open an entity record view
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenEntityRecord(entityName: string, recordPkey: CompositeKey, options?: NavigationOptions): string;
    /**
     * Open a view
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenView(viewId: string, viewName: string, options?: NavigationOptions): string;
    /**
     * Open a dashboard
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenDashboard(dashboardId: string, dashboardName: string, options?: NavigationOptions): string;
    /**
     * Open a report
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenReport(reportId: string, reportName: string, options?: NavigationOptions): string;
    /**
     * Open an artifact
     * Artifacts are versioned content containers (reports, dashboards, UI components, etc.)
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenArtifact(artifactId: string, artifactName?: string, options?: NavigationOptions): string;
    /**
     * Open a dynamic view
     * Dynamic views are entity-based views with custom filters, not saved views
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenDynamicView(entityName: string, extraFilter?: string, options?: NavigationOptions): string;
    /**
     * Open a query
     * Uses Home app if available, otherwise falls back to active app or system app
     */
    OpenQuery(queryId: string, queryName: string, options?: NavigationOptions): string;
    /**
     * Open a new entity record creation form
     * Uses Home app if available, otherwise falls back to active app or system app
     * @param entityName The name of the entity to create a new record for
     * @param options Navigation options including optional newRecordValues for pre-populating fields
     */
    OpenNewEntityRecord(entityName: string, options?: NavigationOptions): string;
    /**
     * Open a universal search results tab for the given query.
     * This is the primary way to open search results from anywhere in the application.
     *
     * @param query The search query text
     * @param searchOptions Optional search-specific options (e.g., minRelevance, scopeIDs)
     * @param options Navigation options
     */
    OpenSearch(query: string, searchOptions?: {
        minRelevance?: number;
        scopeIDs?: string[];
    }, options?: NavigationOptions): string;
    /**
     * Navigate to a nav item by name within the current or specified application.
     * Allows passing additional configuration parameters to merge with the nav item's config.
     * This is useful for cross-resource navigation where a component needs to navigate
     * to another nav item with specific parameters (e.g., navigate to Conversations with a specific conversationId).
     *
     * @param navItemName The label/name of the nav item to navigate to
     * @param configuration Additional configuration to merge (e.g., conversationId, artifactId)
     * @param appId Optional app ID (defaults to current active app)
     * @param options Navigation options
     * @returns The tab ID if successful, null if nav item not found
     */
    OpenNavItemByName(navItemName: string, configuration?: Record<string, unknown>, appId?: string, options?: NavigationOptions): Promise<string | null>;
    /**
     * Switch to an application by ID.
     * This sets the app as active and either opens a specific nav item or creates a default tab.
     * If the requested nav item already has an open tab, switches to that tab instead of creating a new one.
     * @param appId The application ID to switch to
     * @param navItemName Optional name of a nav item to open within the app. If provided, opens that nav item.
     * @param queryParams Optional query params to apply to the target tab. Applied SYNCHRONOUSLY once the
     *                    target tab is active — critical when navigating (e.g. from a Home pin) to an
     *                    app whose resource component is cached: the params must be in the tab config
     *                    BEFORE the tab-container reattaches the cached component, otherwise the cache
     *                    restores its own (stale) saved params and the navigation intent is lost.
     */
    SwitchToApp(appId: string, navItemName?: string, queryParams?: Record<string, string | null>): Promise<void>;
    /**
     * Update the query params for the currently active tab.
     * This updates the tab's configuration and triggers a URL sync via the shell's
     * workspace configuration subscription.
     *
     * Use this instead of directly calling router.navigate() to ensure proper
     * URL management that respects app-scoped routes.
     *
     * @param queryParams Object containing query param key-value pairs.
     *                    Use null values to remove a query param.
     * @example
     * // Add or update query params
     * navigationService.UpdateActiveTabQueryParams({ category: 'abc123', dashboard: 'xyz789' });
     *
     * // Remove a query param
     * navigationService.UpdateActiveTabQueryParams({ category: null });
     */
    UpdateActiveTabQueryParams(queryParams: Record<string, string | null>): void;
    /**
     * Notify subscribers that query params changed on a specific tab.
     * Called by the shell when back/forward navigation changes query params on the active tab.
     * The notification includes the tab ID so only the component in that tab reacts.
     */
    NotifyQueryParamsChanged(tabId: string, params: Record<string, string>): void;
    /**
     * Reactively observe the query params for a specific tab.
     *
     * Backed by the workspace BehaviorSubject, so a subscriber receives the current
     * params *immediately* on subscribe AND every subsequent change — including the
     * deep-link params that the ResourceResolver merges into the tab configuration on
     * a cold/direct URL load.
     *
     * This is the race-free counterpart to {@link NotifyQueryParamsChanged} (a plain
     * Subject that drops events fired before a component has subscribed). A resource
     * component that mounts from workspace restoration can subscribe here and still
     * pick up its initial deep-link state regardless of whether the params landed in
     * the tab config before or after it mounted.
     */
    ObserveTabQueryParams(tabId: string): Observable<Record<string, string>>;
    private shallowParamsEqual;
    /**
     * Apply query params to a specific tab by ID.
     * Merges with any existing query params on the tab. Use null values to remove params.
     */
    private applyQueryParamsToTab;
    static ɵfac: i0.ɵɵFactoryDeclaration<NavigationService, never>;
    static ɵprov: i0.ɵɵInjectableDeclaration<NavigationService>;
}
//# sourceMappingURL=navigation.service.d.ts.map