var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { BaseEngine } from "@memberjunction/core";
import { RegisterForStartup } from "@memberjunction/core";
import { UUIDsEqual } from "@memberjunction/global";
/**
 * SearchEngineBase provides cached access to SearchProvider + Search Scope metadata.
 *
 * Loads all `MJ: Search Providers`, `MJ: Search Scopes`, and the 5 Search Scope child
 * tables (`MJ: Search Scope Providers`, `MJ: Search Scope External Indexes`,
 * `MJ: Search Scope Entities`, `MJ: Search Scope Storage Accounts`, `MJ: AI Agent Search Scopes`)
 * via BaseEngine and provides typed getters and lookups for use anywhere
 * (client or server).
 *
 * The server-side SearchEngine class uses SearchEngineBase.Instance to access cached
 * provider metadata instead of loading directly via RunView. It also uses the scope
 * metadata getters to resolve `SearchScope` + children when a scoped search is requested.
 *
 * Uses BaseEngine for automatic caching and entity-event-based auto-refresh so that
 * provider/scope configuration changes are reflected without manual reload.
 *
 * Usage:
 * ```typescript
 * const base = SearchEngineBase.Instance;
 * await base.Config(false, contextUser);
 *
 * // Get all active providers
 * const activeProviders = base.ActiveProviders;
 *
 * // Find a provider by driver class
 * const vectorProvider = base.GetProviderByDriverClass('VectorSearchProvider');
 *
 * // Resolve an active scope by ID (respects Status + StartAt/EndAt)
 * const scope = base.GetActiveScopeByID('...');
 *
 * // Pull everything needed for a scoped search
 * const bundle = base.GetScopeBundle(scopeId);
 * // -> { Scope, Providers, ExternalIndexes, Entities, StorageAccounts }
 * ```
 */
let SearchEngineBase = class SearchEngineBase extends BaseEngine {
    constructor() {
        super(...arguments);
        this._providers = [];
        this._scopes = [];
        this._scopeProviders = [];
        this._scopeExternalIndexes = [];
        this._scopeEntities = [];
        this._scopeStorageAccounts = [];
        this._agentScopes = [];
    }
    /**
     * Returns the global singleton instance.
     */
    static get Instance() {
        return super.getInstance();
    }
    /**
     * Configures the engine by loading all search provider and scope records from the database.
     * @param forceRefresh - If true, forces a refresh from the database even if data is cached
     * @param contextUser - Optional user context for server-side operations
     * @param provider - Optional metadata provider
     */
    async Config(forceRefresh, contextUser, provider) {
        const configs = [
            {
                Type: 'entity',
                EntityName: 'MJ: Search Providers',
                PropertyName: '_providers',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: Search Scopes',
                PropertyName: '_scopes',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: Search Scope Providers',
                PropertyName: '_scopeProviders',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: Search Scope External Indexes',
                PropertyName: '_scopeExternalIndexes',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: Search Scope Entities',
                PropertyName: '_scopeEntities',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: Search Scope Storage Accounts',
                PropertyName: '_scopeStorageAccounts',
                CacheLocal: true,
            },
            {
                Type: 'entity',
                EntityName: 'MJ: AI Agent Search Scopes',
                PropertyName: '_agentScopes',
                CacheLocal: true,
            }
        ];
        await this.Load(configs, provider, forceRefresh, contextUser);
    }
    // ================================================================
    // Cached data getters — Providers
    // ================================================================
    /** All search provider records (any status) */
    get Providers() {
        return this.GetConfigData('_providers');
    }
    /** Only active search providers, sorted by Priority ascending */
    get ActiveProviders() {
        return this.Providers
            .filter(p => p.Status === 'Active')
            .sort((a, b) => a.Priority - b.Priority);
    }
    /** Active providers that support preview/autocomplete searches */
    get PreviewProviders() {
        return this.ActiveProviders.filter(p => p.SupportsPreview);
    }
    // ================================================================
    // Cached data getters — Scopes
    // ================================================================
    /** All scope records (any status). */
    get Scopes() {
        return this.GetConfigData('_scopes');
    }
    /**
     * Scopes that are currently active AND within their optional StartAt/EndAt time window.
     * Callers should prefer this over `Scopes` when resolving runtime search requests.
     */
    get ActiveScopes() {
        const now = new Date();
        return this.Scopes.filter(s => this.isScopeActiveNow(s, now));
    }
    /** All scope-provider join rows. */
    get ScopeProviders() {
        return this.GetConfigData('_scopeProviders');
    }
    /** All scope-external-index rows. */
    get ScopeExternalIndexes() {
        return this.GetConfigData('_scopeExternalIndexes');
    }
    /** All scope-entity rows. */
    get ScopeEntities() {
        return this.GetConfigData('_scopeEntities');
    }
    /** All scope-storage-account rows. */
    get ScopeStorageAccounts() {
        return this.GetConfigData('_scopeStorageAccounts');
    }
    /** All agent-scope assignment rows. */
    get AgentScopes() {
        return this.GetConfigData('_agentScopes');
    }
    // ================================================================
    // Lookup helpers — Providers
    // ================================================================
    /**
     * Find a provider by its DriverClass key.
     * @param driverClass - The DriverClass value (e.g., 'VectorSearchProvider')
     * @returns The provider entity, or undefined if not found
     */
    GetProviderByDriverClass(driverClass) {
        if (!driverClass)
            return undefined;
        return this._providers.find(p => p.DriverClass === driverClass);
    }
    /**
     * Find a provider by its Name.
     * @param name - The provider name (e.g., 'Semantic')
     * @returns The provider entity, or undefined if not found
     */
    GetProviderByName(name) {
        if (!name)
            return undefined;
        const lower = name.trim().toLowerCase();
        return this._providers.find(p => p.Name.trim().toLowerCase() === lower);
    }
    /**
     * Find a provider by its ID.
     * @param id - The provider record ID
     * @returns The provider entity, or undefined if not found
     */
    GetProviderById(id) {
        if (!id)
            return undefined;
        return this._providers.find(p => UUIDsEqual(p.ID, id));
    }
    /**
     * Get the display label for a source type, resolving from provider metadata.
     * Falls back to the source type string if no provider matches.
     * @param sourceType - The source type key (e.g., 'vector', 'entity')
     */
    GetDisplayNameForSourceType(sourceType) {
        const provider = this.ActiveProviders.find(p => {
            const driverLower = p.DriverClass.toLowerCase();
            return driverLower.startsWith(sourceType.toLowerCase());
        });
        return provider?.DisplayName ?? provider?.Name ?? sourceType;
    }
    /**
     * Get the icon for a source type, resolving from provider metadata.
     * Falls back to a generic icon if no provider matches.
     * @param sourceType - The source type key (e.g., 'vector', 'entity')
     */
    GetIconForSourceType(sourceType) {
        const provider = this.ActiveProviders.find(p => {
            const driverLower = p.DriverClass.toLowerCase();
            return driverLower.startsWith(sourceType.toLowerCase());
        });
        return provider?.Icon ?? 'fa-solid fa-circle';
    }
    // ================================================================
    // Lookup helpers — Scopes
    // ================================================================
    /** Find a scope by ID (any status). */
    GetScopeByID(id) {
        if (!id)
            return undefined;
        return this.Scopes.find(s => UUIDsEqual(s.ID, id));
    }
    /** Find a scope by ID, only returning it if it is currently active. */
    GetActiveScopeByID(id) {
        const scope = this.GetScopeByID(id);
        if (!scope)
            return undefined;
        return this.isScopeActiveNow(scope, new Date()) ? scope : undefined;
    }
    /** Find a scope by Name (any status). */
    GetScopeByName(name) {
        if (!name)
            return undefined;
        const lower = name.trim().toLowerCase();
        return this.Scopes.find(s => s.Name.trim().toLowerCase() === lower);
    }
    /** The first scope with `IsGlobal=true` (there should be exactly one). */
    get GlobalScope() {
        return this.Scopes.find(s => s.IsGlobal);
    }
    /** The first scope with `IsDefault=true` (or `GlobalScope` as a fallback). */
    get DefaultScope() {
        return this.Scopes.find(s => s.IsDefault) ?? this.GlobalScope;
    }
    /** Provider rows (Enabled=true) for a scope. */
    GetProvidersForScope(scopeID) {
        if (!scopeID)
            return [];
        return this.ScopeProviders
            .filter(r => UUIDsEqual(r.SearchScopeID, scopeID) && r.Enabled);
    }
    /** External-index rows for a scope. */
    GetExternalIndexesForScope(scopeID) {
        if (!scopeID)
            return [];
        return this.ScopeExternalIndexes.filter(r => UUIDsEqual(r.SearchScopeID, scopeID));
    }
    /** Entity rows for a scope. */
    GetEntitiesForScope(scopeID) {
        if (!scopeID)
            return [];
        return this.ScopeEntities.filter(r => UUIDsEqual(r.SearchScopeID, scopeID));
    }
    /** Storage-account rows for a scope. */
    GetStorageAccountsForScope(scopeID) {
        if (!scopeID)
            return [];
        return this.ScopeStorageAccounts.filter(r => UUIDsEqual(r.SearchScopeID, scopeID));
    }
    /**
     * Resolve a single scope plus every child collection in one call. Convenience
     * for SearchEngine so it does one lookup per scope instead of five.
     */
    GetScopeBundle(scopeID) {
        const scope = this.GetScopeByID(scopeID);
        if (!scope)
            return undefined;
        return {
            Scope: scope,
            Providers: this.GetProvidersForScope(scopeID),
            ExternalIndexes: this.GetExternalIndexesForScope(scopeID),
            Entities: this.GetEntitiesForScope(scopeID),
            StorageAccounts: this.GetStorageAccountsForScope(scopeID),
        };
    }
    // ================================================================
    // Lookup helpers — Agent <-> Scope
    // ================================================================
    /**
     * Agent-scope rows for an agent, filtered by Phase and current active window.
     * @param agentID - The `MJ: AI Agents` record ID
     * @param phase - Optional phase filter. Rows whose `Phase` is `'Both'` match any phase query.
     */
    GetAgentScopes(agentID, phase) {
        if (!agentID)
            return [];
        const now = new Date();
        return this.AgentScopes.filter(row => {
            if (!UUIDsEqual(row.AgentID, agentID))
                return false;
            if (row.Status !== 'Active')
                return false;
            if (!this.isAgentScopeActiveNow(row, now))
                return false;
            if (phase) {
                if (row.Phase !== phase && row.Phase !== 'Both')
                    return false;
            }
            return true;
        });
    }
    /**
     * The default `IsDefault=true` agent-scope row for an agent, or the highest-priority
     * row (lowest `Priority` value) if no row is marked default.
     */
    GetDefaultAgentScope(agentID) {
        const rows = this.GetAgentScopes(agentID);
        if (rows.length === 0)
            return undefined;
        const explicit = rows.find(r => r.IsDefault);
        if (explicit)
            return explicit;
        return [...rows].sort((a, b) => a.Priority - b.Priority)[0];
    }
    // ================================================================
    // Time-window helpers
    // ================================================================
    isScopeActiveNow(scope, now) {
        if (scope.Status !== 'Active')
            return false;
        if (scope.StartAt && scope.StartAt > now)
            return false;
        if (scope.EndAt && scope.EndAt < now)
            return false;
        return true;
    }
    isAgentScopeActiveNow(row, now) {
        if (row.Status !== 'Active')
            return false;
        if (row.StartAt && row.StartAt > now)
            return false;
        if (row.EndAt && row.EndAt < now)
            return false;
        return true;
    }
};
SearchEngineBase = __decorate([
    RegisterForStartup()
], SearchEngineBase);
export { SearchEngineBase };
//# sourceMappingURL=SearchEngineBase.js.map