import type { BandedReducer } from './data-model/reducers/bandedReducer';
import type { DataChangeDescription } from './dataChangeDescription';
import type { BandedDomain, BandedDomainConfig } from './dataDomain';
import type { DataSet } from './dataSet';
import type { RangeLookup } from './rangeLookup';
import type { SortOrder } from './sortOrder';
export interface ScopeProvider {
    id: string;
}
export interface DataGroup {
    keys: any[];
    datumIndices: readonly (readonly number[])[];
    aggregation: any[][];
    validScopes: Set<ScopeId>;
}
export interface UngroupedDataItem<I, D, V> {
    index: I;
    keys: any[];
    values: V;
    aggValues?: [number, number][];
    datum: D;
    validScopes?: Set<string>;
}
export declare const KEY_SORT_ORDERS: unique symbol;
export declare const COLUMN_SORT_ORDERS: unique symbol;
export declare const DOMAIN_RANGES: unique symbol;
export declare const DOMAIN_BANDS: unique symbol;
export declare const REDUCER_BANDS: unique symbol;
export interface BandedReducerStats extends Record<string, number> {
    totalBands: number;
    dirtyBands: number;
    dataSize: number;
    scanRatio: number;
    cacheHits: number;
}
export declare const SHARED_ZERO_INDICES: readonly number[];
export type ScopeId = string;
export type ProcessedValue = {
    value: unknown;
    missing: boolean;
    valid: boolean;
};
export type SortOrderEntry = {
    sortOrder: SortOrder;
    isUnique?: boolean;
    isDirty?: boolean;
};
export type ProcessedValueEntry = {
    value: any;
    valid: boolean;
};
export interface GroupDatumIteratorOutput {
    group: DataGroup;
    groupIndex: number;
    columnIndex: number;
    datumIndex: number;
}
export type InsertionCacheValue = {
    keys: Map<number, ProcessedValueEntry>;
    values: Map<number, ProcessedValueEntry>;
    hasInvalidKey: boolean;
    hasInvalidValue: boolean;
};
export type InsertionCache = Map<number, InsertionCacheValue>;
export type ColumnBatch = [ScopeId, number[], unknown[][], Set<ScopeId>, boolean[] | undefined, boolean[] | undefined];
export type MergedColumnBatch = [
    ScopeId[],
    number[],
    unknown[][],
    Set<ScopeId>,
    boolean[] | undefined,
    boolean[] | undefined
];
export interface CommonMetadata<D> {
    input: {
        count: number;
    };
    scopes: Set<ScopeId>;
    dataSources: Map<ScopeId, DataSet<unknown>>;
    invalidKeys: Map<ScopeId, boolean[]> | undefined;
    invalidKeyCount: Map<ScopeId, number> | undefined;
    invalidData: Map<ScopeId, boolean[]> | undefined;
    invalidDataCount: Map<ScopeId, number> | undefined;
    keys: Map<ScopeId, unknown[]>[];
    columns: any[][];
    columnScopes: Set<ScopeId>[];
    columnNeedValueOf?: boolean[];
    domain: {
        keys: any[][];
        values: any[][];
        groups?: any[][];
        aggValues?: [number, number][];
    };
    reduced?: {
        diff?: Record<string, ProcessedOutputDiff>;
        smallestKeyInterval?: number;
        largestKeyInterval?: number;
        sortedGroupDomain?: any[][];
        animationValidation?: {
            uniqueKeys: boolean;
            orderedKeys: boolean;
        };
    };
    defs: {
        keys: (Scoped & DatumPropertyDefinition<keyof D>)[];
        values: (Scoped & DatumPropertyDefinition<keyof D>)[];
        allScopesHaveSameDefs: boolean;
    };
    partialValidDataCount: number;
    time: number;
    /** Monotonically increasing version counter, incremented on every processing cycle */
    version: number;
    optimizations?: OptimizationMetadata;
    [DOMAIN_RANGES]: Map<string, RangeLookup>;
    [KEY_SORT_ORDERS]: Map<number, SortOrderEntry>;
    [COLUMN_SORT_ORDERS]: Map<number, SortOrderEntry>;
    [DOMAIN_BANDS]: Map<InternalDatumPropertyDefinition<any>, BandedDomain>;
    [REDUCER_BANDS]?: Map<ReducerBandKey, BandedReducer>;
    changeDescription?: DataChangeDescription;
}
export interface UngroupedData<D> extends CommonMetadata<D> {
    type: 'ungrouped';
    aggregation?: [number, number][][];
}
export interface GroupedData<D> extends CommonMetadata<D> {
    type: 'grouped';
    groups: DataGroup[];
    groupsUnique: boolean;
}
export type ProcessedOutputDiff = {
    changed: boolean;
    added: Set<string>;
    updated: Set<string>;
    removed: Set<string>;
    moved: Set<string>;
};
export interface ProcessedDataDef {
    index: number;
    def: PropertyDefinition<any>;
}
export type ProcessedData<D> = UngroupedData<D> | GroupedData<D>;
/** Metadata about applied/skipped optimizations for debugging */
export interface OptimizationMetadata {
    /** Was reprocessing path used? */
    reprocessing?: {
        applied: boolean;
        reason?: string;
    };
    /** Domain banding optimization per definition */
    domainBanding?: {
        keyDefs: Array<{
            property: string;
            applied: boolean;
            reason?: string;
            stats?: {
                totalBands: number;
                dirtyBands: number;
                dataSize: number;
                scanRatio: number;
            };
        }>;
        valueDefs: Array<{
            property: string;
            applied: boolean;
            reason?: string;
            stats?: {
                totalBands: number;
                dirtyBands: number;
                dataSize: number;
                scanRatio: number;
            };
        }>;
    };
    /** Shared datum indices optimization (grouped data only) */
    sharedDatumIndices?: {
        applied: boolean;
        sharedGroupCount: number;
        totalGroupCount: number;
    };
    /** Batch merging optimization */
    batchMerging?: {
        originalBatchCount: number;
        mergedBatchCount: number;
        mergeRatio: number;
    };
    /** Reducer banding optimization */
    reducerBanding?: {
        reducers: Array<{
            property: string;
            applied: boolean;
            reason?: string;
            stats?: BandedReducerStats;
        }>;
    };
    /** Overall performance metrics */
    performance?: {
        processingTime: number;
        pathTaken: 'full-process' | 'reprocess';
    };
}
export type DatumPropertyType = 'range' | 'category';
export type MissMap = Map<string, number>;
export type GroupingFn<K> = (keys: unknown[]) => K[];
export type GroupByFn = (extractedData: UngroupedData<any>) => GroupingFn<any>;
export type DataModelOptions<K, Grouped extends boolean | undefined, IsScoped extends boolean = true> = {
    props: PropertyDefinition<K, IsScoped>[];
    groupByKeys?: Grouped;
    groupByData?: Grouped;
    groupByFn?: GroupByFn;
    domainBandingConfig?: BandedDomainConfig;
};
export type PropertyDefinition<K, IsScoped = false> = (DatumPropertyDefinition<K> & (IsScoped extends true ? Scoped : unknown)) | AggregatePropertyDefinition<any, any, any> | (PropertyValueProcessorDefinition<any> & (IsScoped extends true ? Scoped : unknown)) | GroupValueProcessorDefinition<any, any> | ReducerOutputPropertyDefinition<any> | ProcessorOutputPropertyDefinition<any>;
export type ProcessorFn = (datum: unknown, index: number) => unknown;
export type PropertyId<K extends string> = K | {
    id: string;
};
export type Scoped = {
    /** Scope(s) a property definition belongs to (typically the defining entities unique identifier). */
    scopes: ScopeId[];
};
export type PropertyIdentifiers = {
    id?: string;
    /** Map<Scope, Set<Id>> */
    idsMap?: Map<string, Set<string>>;
    /** Optional group a property belongs to, for cross-scope combination. */
    groupId?: string;
};
export type PropertySelectors = {
    /** Optional group a property belongs to, for cross-scope combination. */
    matchGroupIds?: string[];
};
export type DatumPropertyDefinition<K> = PropertyIdentifiers & {
    type: 'key' | 'value';
    valueType: DatumPropertyType;
    property: K;
    forceValue?: any;
    includeProperty?: boolean;
    invalidValue?: any;
    missing?: MissMap;
    missingValue?: any;
    separateNegative?: boolean;
    validation?: (value: any, datum: any, index: number) => boolean;
    processor?: () => ProcessorFn;
    allowNullKey?: boolean;
};
export type InternalDefinition<IsScoped extends boolean> = {
    index: number;
} & (IsScoped extends true ? Scoped : unknown);
export type InternalDatumPropertyDefinition<K> = DatumPropertyDefinition<K> & InternalDefinition<true> & {
    missing: MissMap;
};
export type AggregatePropertyDefinition<D, K extends keyof D & string, R = [number, number], R2 = R> = Omit<PropertyIdentifiers, 'scopes'> & PropertySelectors & {
    type: 'aggregate';
    aggregateFunction: (values: D[K][], keys?: D[K][]) => R;
    groupAggregateFunction?: (next?: R, acc?: R2) => R2;
    finalFunction?: (result: R2) => [number, number];
};
export type GroupValueAdjustFn<D, K extends keyof D & string> = (columns: D[K][][], indexes: number[], dataGroup: DataGroup, groupIndex: number) => void;
export type GroupValueProcessorDefinition<D, K extends keyof D & string> = PropertyIdentifiers & PropertySelectors & {
    type: 'group-value-processor';
    /**
     * Outer function called once per all data processing; inner function called once per group;
     * innermost called once per datum.
     */
    adjust: () => () => GroupValueAdjustFn<D, K>;
    /**
     * Indicates whether this processor supports incremental reprocessing.
     * When true, the processor can safely be reapplied to modified data without
     * causing double-processing issues.
     */
    supportsReprocessing?: boolean;
};
export type PropertyValueAdjustFn<D> = (processedData: ProcessedData<D>, valueIndex: number) => void;
export type PropertyValueProcessorDefinition<D> = PropertyIdentifiers & {
    type: 'property-value-processor';
    property: string;
    adjust: () => PropertyValueAdjustFn<D>;
};
export type ReducerOutputTypes = NonNullable<UngroupedData<any>['reduced']>;
export type ReducerOutputKeys = keyof ReducerOutputTypes;
export type ReducerBandKey = Extract<ReducerOutputKeys, string>;
export type ReducerOutputPropertyDefinition<P extends ReducerOutputKeys = ReducerOutputKeys> = PropertyIdentifiers & {
    type: 'reducer';
    property: P;
    initialValue?: ReducerOutputTypes[P];
    reducer: () => (acc: ReducerOutputTypes[P], keys: unknown[]) => ReducerOutputTypes[P];
    supportsBanding?: boolean;
    combineResults?: (bandResults: ReducerOutputTypes[P][]) => ReducerOutputTypes[P];
    needsOverlap?: boolean;
};
export type ProcessorOutputPropertyDefinition<P extends ReducerOutputKeys = ReducerOutputKeys> = PropertyIdentifiers & {
    type: 'processor';
    property: P;
    calculate: (data: ProcessedData<any>, previousValue: ReducerOutputTypes[P] | undefined) => ReducerOutputTypes[P];
    incrementalCalculate?: (data: ProcessedData<any>, previousValue: ReducerOutputTypes[P] | undefined) => ReducerOutputTypes[P];
};
