import type { Datum } from "../charts/shared/datumTypes";
import { type Quadtree } from "d3-quadtree";
import { RingBuffer } from "../realtime/RingBuffer";
import type { Changeset, StreamChartType, StreamScales, StreamLayout, SceneNode, PointSceneNode, CandlestickStyle, Style, ArrowOfTime, WindowMode, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, CurveType, BarStyle, ThemeSemanticColors } from "./types";
import type { ActiveTransition } from "./pipelineTransitionUtils";
export interface PipelineConfig {
    chartType: StreamChartType;
    runtimeMode?: "streaming" | "bounded";
    windowSize: number;
    windowMode: WindowMode;
    arrowOfTime: ArrowOfTime;
    extentPadding: number;
    /** Pixel inset on scale ranges to prevent glyph clipping at chart edges. Default 0. */
    scalePadding?: number;
    maxCapacity?: number;
    xAccessor?: string | ((d: Datum) => number);
    yAccessor?: string | ((d: Datum) => number);
    timeAccessor?: string | ((d: Datum) => number);
    valueAccessor?: string | ((d: Datum) => number);
    colorAccessor?: string | ((d: Datum) => string);
    sizeAccessor?: string | ((d: Datum) => number);
    groupAccessor?: string | ((d: Datum) => string);
    categoryAccessor?: string | ((d: Datum) => string);
    lineDataAccessor?: string;
    xScaleType?: "linear" | "log" | "time";
    yScaleType?: "linear" | "log";
    xExtent?: [number | undefined, number | undefined] | [number];
    yExtent?: [number | undefined, number | undefined] | [number];
    sizeRange?: [number, number];
    binSize?: number;
    normalize?: boolean;
    openAccessor?: string | ((d: Datum) => number);
    highAccessor?: string | ((d: Datum) => number);
    lowAccessor?: string | ((d: Datum) => number);
    closeAccessor?: string | ((d: Datum) => number);
    candlestickStyle?: CandlestickStyle;
    /** Internal: set by PipelineStore when open/close accessors are both missing */
    candlestickRangeMode?: boolean;
    boundsAccessor?: string | ((d: Datum) => number);
    boundsStyle?: any;
    y0Accessor?: string | ((d: Datum) => number);
    gradientFill?: {
        topOpacity: number;
        bottomOpacity: number;
    } | {
        colorStops: Array<{
            offset: number;
            color: string;
        }>;
    };
    areaGroups?: Set<string>;
    lineGradient?: {
        colorStops: Array<{
            offset: number;
            color: string;
        }>;
    };
    lineStyle?: any;
    pointStyle?: (d: Datum) => Style & {
        r?: number;
    };
    areaStyle?: (d: Datum) => Style;
    swarmStyle?: {
        radius?: number;
        fill?: string;
        opacity?: number;
        stroke?: string;
        strokeWidth?: number;
    };
    waterfallStyle?: {
        positiveColor?: string;
        negativeColor?: string;
        connectorStroke?: string;
        connectorWidth?: number;
        gap?: number;
        stroke?: string;
        strokeWidth?: number;
    };
    colorScheme?: string | string[];
    /** Theme categorical palette — used as fallback when colorScheme is not an explicit array */
    themeCategorical?: string[];
    /**
     * Theme-resolved semantic role colors. Scene builders use these as the
     * default before falling back to hardcoded hex. Populated by the Stream
     * Frame from the in-memory `SemioticTheme.colors` object at render time
     * — the values are concrete hex (or whatever the preset declares), not
     * `var(...)` strings, and so this channel does NOT participate in the
     * DOM CSS cascade. Changing the ambient theme (`<ThemeProvider>`) or
     * swapping to a nested provider is how you override these values.
     *
     * Per-scope overrides via CSS custom properties
     * (e.g. `<div style={{ "--semiotic-danger": "#c00" }}>`) work only for
     * values a user explicitly passes through as `var(--...)` strings in
     * chart props — those are resolved via `getComputedStyle` in the
     * canvas renderer at paint time (see `resolveCSSColor.ts`). The theme
     * defaults in this field don't read CSS.
     */
    themeSemantic?: ThemeSemanticColors;
    /** Theme sequential scheme name (e.g. "blues") — fallback when `colorScheme` is not explicitly set for magnitude encodings (heatmap, choropleth, size). */
    themeSequential?: string;
    /** Theme diverging scheme name (e.g. "RdBu") — fallback when `colorScheme` is not explicitly set for midpoint encodings (likert, bivariate, ± deviation). */
    themeDiverging?: string;
    barColors?: Record<string, string>;
    /** Histogram bar style — fill/stroke/strokeWidth/gap. Accepted by RealtimeHistogram and routed through to the bar scene builder. */
    barStyle?: BarStyle;
    annotations?: Datum[];
    decay?: DecayConfig;
    pulse?: PulseConfig;
    transition?: TransitionConfig;
    /** Whether to animate elements on first render (points scale up, lines/areas clip from left, rects grow from baseline) */
    introAnimation?: boolean;
    staleness?: StalenessConfig;
    heatmapAggregation?: "count" | "sum" | "mean";
    heatmapXBins?: number;
    heatmapYBins?: number;
    showValues?: boolean;
    heatmapValueFormat?: (v: number) => string;
    pointIdAccessor?: string | ((d: Datum) => string);
    curve?: CurveType;
}
export declare class PipelineStore {
    private buffer;
    private xExtent;
    private yExtent;
    private config;
    private growingCap;
    private getX;
    private getY;
    private getGroup;
    private getCategory;
    private getSize;
    private getColor;
    private getBounds;
    private getY0;
    private getOpen;
    private getHigh;
    private getLow;
    private getClose;
    private getPointId;
    private timestampBuffer;
    activeTransition: ActiveTransition | null;
    private _hasRenderedOnce;
    private prevPositionMap;
    /** Previous line/area path arrays for path interpolation */
    private prevPathMap;
    /** Exit nodes awaiting fade-out removal */
    exitNodes: SceneNode[];
    lastIngestTime: number;
    /** Unified color map cache keyed by sorted category set — shared across point, swarm, etc. */
    private _colorMapCache;
    /** Separate group→color map for resolveGroupColor (insertion-order based, never invalidates _colorMapCache).
     *  FIFO-bounded to `GROUP_COLOR_MAP_CAP` entries — in long-running streams with unique group IDs (e.g. UUIDs
     *  as `lineBy` keys) this would otherwise grow unboundedly. Evicted groups that re-appear get a new palette
     *  slot; stable color assignment is only guaranteed for the most-recent `CAP` unique groups. */
    private _groupColorMap;
    /** Monotonic counter for group-color palette indexing. Decoupled from `_groupColorMap.size` so FIFO eviction
     *  doesn't cause new groups to collide with existing entries on a shrunk map. */
    private _groupColorCounter;
    private static readonly GROUP_COLOR_MAP_CAP;
    private _barCategoryCache;
    /** Sorted bin boundary values from the last bar scene build (for data-driven brush snapping) */
    private _binBoundaries;
    /** Cache stacked area cumulative sums to skip recalculation when buffer hasn't changed */
    private _stackExtentCache;
    /** Monotonic counter incremented on each ingest — used as part of cache keys */
    private _ingestVersion;
    /** Cached materialized array from buffer.toArray() — only rebuilt when buffer changes */
    private _bufferArrayCache;
    /** True when the buffer has been mutated since last toArray() call */
    private _bufferDirty;
    private needsFullRebuild;
    private lastLayout;
    scales: StreamScales | null;
    scene: SceneNode[];
    version: number;
    /** True when the x accessor returns Date objects (auto-detected on first data ingestion) */
    xIsDate: boolean;
    private _quadtree;
    /** Largest visual point radius in the current scene. The hit tester uses
     *  this to widen its quadtree query so points with big radii (bubble) don't
     *  fall outside the search region. */
    private _maxPointRadius;
    private static readonly QUADTREE_THRESHOLD;
    constructor(config: PipelineConfig);
    /**
     * Process a changeset from DataSourceAdapter.
     * Returns true if the scene needs re-rendering.
     */
    ingest(changeset: Changeset): boolean;
    /**
     * Recompute scales and scene graph for the current buffer contents.
     */
    computeScene(layout: StreamLayout): void;
    /**
     * Build or clear the quadtree spatial index for point scene nodes.
     * Only built for scatter/bubble charts with >QUADTREE_THRESHOLD points.
     */
    private rebuildQuadtree;
    /**
     * Get the quadtree spatial index, if available.
     * Returns null when chart type is not scatter/bubble or point count is below threshold.
     */
    get quadtree(): Quadtree<PointSceneNode> | null;
    /** Largest visual point radius in the current scene. */
    get maxPointRadius(): number;
    /**
     * Remap existing scene node coordinates for a new layout size.
     * Proportionally scales all pixel coordinates without rebuilding from data.
     */
    private remapScene;
    private buildSceneNodes;
    private resolveBoundsStyle;
    computeDecayOpacity(bufferIndex: number, bufferSize: number): number;
    private applyDecay;
    private applyPulse;
    get hasActivePulses(): boolean;
    private get transitionContext();
    private snapshotPositions;
    /** Synthesize a zero-state prevPositionMap/prevPathMap for animated intro (first render). */
    private synthesizeIntroPositions;
    private startTransition;
    advanceTransition(now: number): boolean;
    private groupData;
    /**
     * Resolve a category→color map from data using the colorAccessor.
     * Caches the result in _colorMapCache keyed by `_ingestVersion` (fast path)
     * and a sorted-category fingerprint (so palette/scheme changes still
     * invalidate). Multiple scene builders within one frame skip the data scan
     * entirely after the first call.
     */
    private resolveColorMap;
    private resolveLineStyle;
    private resolveAreaStyle;
    /** Resolve a group name to a color from the cached color map or a dedicated group palette.
     *  First checks _colorMapCache (populated by resolveColorMap when colorAccessor is set).
     *  Falls back to _groupColorMap (insertion-order, never mutates _colorMapCache).
     *
     *  FIFO-evicts the oldest entry when the map exceeds `GROUP_COLOR_MAP_CAP`. The palette index
     *  uses `_groupColorCounter` (monotonic, decoupled from map size) so eviction doesn't cause
     *  new groups to collide with existing entries on a shrunk map. */
    private resolveGroupColor;
    /**
     * Return a cached materialized array of the buffer contents.
     * Only calls buffer.toArray() when the buffer has actually changed
     * (new push, resize, or clear), avoiding per-frame allocation on
     * transition ticks, hover redraws, and other non-data-changing renders.
     */
    private getBufferArray;
    getData(): Datum[];
    /**
     * Remove data points by ID. Requires pointIdAccessor to be configured.
     * Returns the removed items. Marks the store dirty for scene rebuild.
     */
    remove(id: string | string[]): Datum[];
    /**
     * Update data points by ID. Requires pointIdAccessor.
     * The updater receives the current datum and returns the replacement.
     * Returns the previous values. Extents and scene are marked dirty.
     */
    update(id: string | string[], updater: (d: Datum) => Datum): Datum[];
    /** Returns sorted bin boundary values from the last bar scene build. Persists until clear() or the next bar scene build. */
    getBinBoundaries(): number[];
    getExtents(): {
        x: [number, number];
        y: [number, number];
    } | null;
    clear(): void;
    get size(): number;
    getBuffer(): RingBuffer<Datum>;
    getXAccessor(): (d: Datum) => number;
    getYAccessor(): (d: Datum) => number;
    getCategoryAccessor(): ((d: Datum) => string) | undefined;
    updateConfig(config: Partial<PipelineConfig>): void;
}
