/**
 * @fileoverview Pure, framework-agnostic helpers for the Knowledge Hub
 * "Analytics" resource's AI-agent integration.
 *
 * These functions are free of Angular / component dependencies so they can be
 * unit-tested in isolation. The component
 * ({@link AnalyticsResourceComponent}) supplies a plain snapshot of its current
 * state (active tab, filters, and the per-tab aggregate values it has computed)
 * and these helpers shape it into the key-value `AgentContext` object that flows
 * to the async chat agent and the realtime co-agent via
 * `NavigationService.SetAgentContext`. They also resolve agent-supplied
 * references (a source by name, a tab id) the way a user refers to them.
 *
 * 🚨 SAFETY: these helpers only SHAPE read-only aggregate state and RESOLVE
 * references — no mutation, no side effects. Nothing here exposes raw record
 * bodies; only the aggregate metrics, filters, and salient display names the
 * surface already shows on screen.
 */
/** The analytics navigation tabs the surface exposes. */
export const ANALYTICS_TABS = ['overview', 'tags', 'sources', 'pipeline', 'quality', 'cost'];
/** Type-guard for an Analytics tab id; keeps the switch tool tolerant of bad input. */
export function isValidAnalyticsTab(tab) {
    return typeof tab === 'string' && ANALYTICS_TABS.includes(tab);
}
/** The date-range filter labels the surface offers. */
export const ANALYTICS_DATE_RANGES = ['7D', '30D', '90D', 'YTD', 'All'];
/** Type-guard for a date-range label; keeps the date-range tool tolerant. */
export function isValidAnalyticsDateRange(range) {
    return typeof range === 'string' && ANALYTICS_DATE_RANGES.includes(range);
}
/** Upper bound on how many list entries we publish in any one context field. */
export const ANALYTICS_CONTEXT_LIST_CAP = 25;
/** Cap an array to {@link ANALYTICS_CONTEXT_LIST_CAP} entries. Pure; never mutates input. */
export function capAnalyticsList(items) {
    return items.slice(0, ANALYTICS_CONTEXT_LIST_CAP);
}
/**
 * Resolve an agent-supplied name reference (case-insensitive) against a list of
 * available names. Tries exact match first, then first case-insensitive
 * *contains* match. Pure + deterministic; returns the matched name or null.
 *
 * @param input - whatever the agent passed (a source name, an entity-filter label)
 * @param names - the names available on the surface
 */
export function resolveAnalyticsName(input, names) {
    const needle = (input ?? '').trim().toLowerCase();
    if (!needle) {
        return null;
    }
    const exact = names.find(n => n.toLowerCase() === needle);
    if (exact) {
        return exact;
    }
    return names.find(n => n.toLowerCase().includes(needle)) ?? null;
}
/**
 * A "no match" tolerant error for a name lookup. Lists the available names
 * (bounded) so the agent can retry. Never throws.
 */
export function buildAnalyticsNotFoundError(input, availableNames, noun) {
    const sample = capAnalyticsList(availableNames);
    const listed = sample.length > 0 ? sample.join(', ') : '(none available)';
    const more = availableNames.length > sample.length ? `, … (${availableNames.length} total)` : '';
    return {
        Success: false,
        ErrorMessage: `No ${noun} matches "${input}". Available ${noun}s: ${listed}${more}.`,
    };
}
/** Build the always-on KPI / filter slice shared across every tab. */
function buildCommonSlice(input) {
    return {
        ActiveTab: input.ActiveTab,
        DateRange: input.DateRange,
        EntityFilter: input.EntityFilter,
        AvailableEntityFilters: capAnalyticsList(input.EntityFilterOptions),
        IsLoading: input.IsLoading,
        DrillDownOpen: input.DrillDownTarget != null,
        DrillDownTarget: input.DrillDownTarget,
        KPIs: capAnalyticsList(input.KPIs.map(k => ({ Label: k.Label, Value: k.Value, Delta: k.Delta }))),
        PipelineStatusText: input.PipelineStatusText,
        PipelineStatusOk: input.PipelineStatusOk,
    };
}
/** Build the tags-tab deep slice. */
function buildTagsSlice(input) {
    const slice = {
        TopTags: capAnalyticsList(input.TopTags),
        TopTagCount: input.TopTags.length,
    };
    if (input.CoOccurrencePairs.length > 0) {
        slice['CoOccurrencePairs'] = capAnalyticsList(input.CoOccurrencePairs);
        slice['CoOccurrenceLastComputed'] = input.CoOccurrenceLastComputed;
    }
    return slice;
}
/** Build the sources-tab deep slice. */
function buildSourcesSlice(input) {
    return {
        SourceComparison: capAnalyticsList(input.SourceComparison),
        SourceCount: input.SourceComparison.length,
        SelectedSourceName: input.SelectedSourceName || null,
        AvailableSourceNames: capAnalyticsList(input.SourceComparison.map(s => s.Name)),
    };
}
/** Build the quality-tab deep slice. */
function buildQualitySlice(input) {
    return {
        QualityScore: input.QualityScore,
        ConfidenceStats: capAnalyticsList(input.ConfidenceStats),
    };
}
/** Build the cost-tab deep slice. */
function buildCostSlice(input) {
    return {
        CostKPIs: capAnalyticsList(input.CostKPIs),
    };
}
/**
 * Build the agent-visible context object for the Analytics surface. The active
 * tab decides which deep slice is merged onto the always-on common slice
 * (mode-scoped context). Pure function (no `this`) so it's unit-testable.
 *
 * @param input - the component's current state snapshot
 * @returns a flat key-value object suitable for `SetAgentContext`
 */
export function buildAnalyticsAgentContext(input) {
    const context = buildCommonSlice(input);
    switch (input.ActiveTab) {
        case 'tags':
            return { ...context, ...buildTagsSlice(input) };
        case 'sources':
            return { ...context, ...buildSourcesSlice(input) };
        case 'quality':
            return { ...context, ...buildQualitySlice(input) };
        case 'cost':
            return { ...context, ...buildCostSlice(input) };
        case 'overview':
        case 'pipeline':
        default:
            return context;
    }
}
//# sourceMappingURL=analytics-agent-context.js.map