import type { ReactNode } from "react";
import type { OnObservationCallback } from "../store/ObservationStore";
import type { HoverData, AnnotationContext } from "../realtime/types";
import type { LegendGroup, LegendLayout } from "../types/legendTypes";
import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, ThemeSemanticColors, SceneDatum } from "./types";
import type { AnimateProp } from "./pipelineTransitionUtils";
import type { Datum } from "../charts/shared/datumTypes";
import type { AutoPlaceAnnotations } from "../recipes/annotationLayout";
export interface TensionConfig {
    weightChange: number;
    newEdge: number;
    newNode: number;
    threshold: number;
    transitionDuration: number;
}
export declare const DEFAULT_TENSION_CONFIG: TensionConfig;
export interface RealtimeNode {
    id: string;
    x0: number;
    x1: number;
    y0: number;
    y1: number;
    x: number;
    y: number;
    width: number;
    height: number;
    _prevX0?: number;
    _prevX1?: number;
    _prevY0?: number;
    _prevY1?: number;
    _targetX0?: number;
    _targetX1?: number;
    _targetY0?: number;
    _targetY1?: number;
    value: number;
    depth?: number;
    data?: Datum;
    createdByFrame?: boolean;
    sourceLinks?: RealtimeEdge[];
    targetLinks?: RealtimeEdge[];
    _pulseIntensity?: number;
    _pulseColor?: string;
    _pulseGlowRadius?: number;
    /**
     * @internal Hierarchy-layout-only extension fields. Set by
     * `hierarchyLayoutPlugin` / `orbitLayoutPlugin` during layout and
     * read by `hierarchySceneBuilders`. Typed `unknown` because the d3
     * `HierarchyNode` shape is layout-specific (rectangular, circular,
     * point) — consumers narrow with the structural fields they need.
     */
    __hierarchyNode?: unknown;
    /** @internal Circle-pack layout radius. Set by `hierarchyLayoutPlugin`. */
    __radius?: number;
    /**
     * @internal Chord-layout extension. Carries the start/end angles
     * for the arc segment representing this node, computed by
     * `chordLayoutPlugin` and read by its `buildScene`. Concretely
     * typed (unlike `__hierarchyNode`) because chord is the only
     * layout that writes this field, so the shape is fixed — no
     * narrowing-at-read needed. `__` prefix matches the convention
     * used by `__hierarchyNode` / `__radius` on this same interface.
     */
    __arcData?: {
        startAngle: number;
        endAngle: number;
    };
}
export interface RealtimeEdge {
    source: RealtimeNode | string;
    target: RealtimeNode | string;
    value: number;
    y0: number;
    y1: number;
    sankeyWidth: number;
    _prevY0?: number;
    _prevY1?: number;
    _prevSankeyWidth?: number;
    _targetY0?: number;
    _targetY1?: number;
    _targetSankeyWidth?: number;
    /** Set during intro animation to allow edge interpolation from width 0 */
    _introFromZero?: boolean;
    direction?: string;
    circular?: boolean;
    circularPathData?: CircularPathData;
    bezier?: BezierCache;
    data?: Datum;
    /** Unique key for this edge (supports parallel edges between same node pair) */
    _edgeKey?: string;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _pulseGlowRadius?: number;
    /** @internal Circular sankey layout fields */
    _circularWidth?: number;
    _circularStub?: boolean;
    /**
     * @internal Chord-layout extension. Carries the d3-chord-generated
     * source/target arc spans for this edge, set by `chordLayoutPlugin`
     * during `computeLayout` and read by its `buildScene`. Typed
     * `unknown` because the d3 `Chord` interface lives in `d3-chord`
     * and importing the type here would couple `networkTypes` to that
     * dep — consumers narrow at the read site. `__` prefix matches the
     * `_circularWidth` / `_circularStub` internal-field convention on
     * this same interface.
     */
    __chordData?: unknown;
}
export interface BezierPoint {
    x: number;
    y: number;
}
export interface BezierCache {
    circular: boolean;
    points?: [BezierPoint, BezierPoint, BezierPoint, BezierPoint];
    segments?: Array<[BezierPoint, BezierPoint, BezierPoint, BezierPoint]>;
    halfWidth: number;
}
export interface CircularPathData {
    sourceX: number;
    targetX: number;
    sourceY: number;
    targetY: number;
    rightFullExtent: number;
    leftFullExtent: number;
    verticalFullExtent: number;
    rightInnerExtent: number;
    leftInnerExtent: number;
    verticalRightInnerExtent: number;
    verticalLeftInnerExtent: number;
    rightSmallArcRadius: number;
    rightLargeArcRadius: number;
    leftSmallArcRadius: number;
    leftLargeArcRadius: number;
    sourceWidth: number;
    rightNodeBuffer: number;
    leftNodeBuffer: number;
    arcRadius: number;
}
export interface Particle {
    t: number;
    offset: number;
    edgeIndex: number;
    active: boolean;
    x: number;
    y: number;
}
export interface ParticleStyle {
    radius?: number;
    color?: string | ((edge: RealtimeEdge, node: RealtimeNode) => string);
    /** Color particles by source or target node (default: "source") */
    colorBy?: "source" | "target";
    opacity?: number;
    speedMultiplier?: number;
    maxPerEdge?: number;
    spawnRate?: number;
    /** Scale particle speed proportional to edge value (higher value = faster). Default: false */
    proportionalSpeed?: boolean;
}
export declare const DEFAULT_PARTICLE_STYLE: Required<Pick<ParticleStyle, "radius" | "opacity" | "speedMultiplier" | "maxPerEdge" | "spawnRate">>;
export interface EdgePush {
    source: string;
    target: string;
    value: number;
}
export type { HoverData };
export type RealtimeNetworkFrameHandle = StreamNetworkFrameHandle;
export interface RealtimeNetworkFrameProps {
    initialEdges?: EdgePush[];
    size?: [number, number];
    margin?: {
        top?: number;
        right?: number;
        bottom?: number;
        left?: number;
    };
    orientation?: "horizontal" | "vertical";
    nodeAlign?: "justify" | "left" | "right" | "center";
    nodePaddingRatio?: number;
    nodeWidth?: number;
    tensionConfig?: Partial<TensionConfig>;
    showParticles?: boolean;
    particleStyle?: ParticleStyle;
    colorBy?: string | ((d: RealtimeNode) => string);
    colorScheme?: string | string[];
    edgeColorBy?: "source" | "target" | ((d: RealtimeEdge) => string);
    edgeOpacity?: number;
    nodeLabel?: string | ((d: RealtimeNode) => string);
    showLabels?: boolean;
    enableHover?: boolean;
    tooltipContent?: (d: {
        type: "node" | "edge";
        data: Datum | null;
    }) => ReactNode;
    onTopologyChange?: (nodes: RealtimeNode[], edges: RealtimeEdge[]) => void;
    background?: string;
    className?: string;
}
export type NetworkChartType = "force" | "sankey" | "chord" | "tree" | "cluster" | "treemap" | "circlepack" | "orbit" | "partition";
/** Circle node — used by force, tree, cluster, circlepack */
export interface NetworkCircleNode {
    type: "circle";
    cx: number;
    cy: number;
    r: number;
    style: Style;
    datum: SceneDatum;
    id?: string;
    label?: string;
    depth?: number;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _pulseGlowRadius?: number;
}
/** Rect node — used by sankey, treemap, partition */
export interface NetworkRectNode {
    type: "rect";
    x: number;
    y: number;
    w: number;
    h: number;
    style: Style;
    datum: SceneDatum;
    id?: string;
    label?: string;
    depth?: number;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _pulseGlowRadius?: number;
}
/** Arc node — used by chord */
/** Arc node — used by chord. Angles in canvas convention (0 = 3 o'clock). */
export interface NetworkArcNode {
    type: "arc";
    cx: number;
    cy: number;
    innerR: number;
    outerR: number;
    /** Start angle in radians, canvas convention (0 = 3 o'clock, positive = clockwise) */
    startAngle: number;
    /** End angle in radians, canvas convention */
    endAngle: number;
    style: Style;
    datum: SceneDatum;
    id?: string;
    label?: string;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _pulseGlowRadius?: number;
}
/** Line edge — used by force */
export interface NetworkLineEdge {
    type: "line";
    x1: number;
    y1: number;
    x2: number;
    y2: number;
    style: Style;
    datum: SceneDatum;
    _pulseIntensity?: number;
    _pulseColor?: string;
}
/** Bezier band edge — used by sankey */
export interface NetworkBezierEdge {
    type: "bezier";
    pathD: string;
    /** When false, the hit tester skips this edge. Used for
     *  decorative scene-edges like ProcessSankey's gradient stubs —
     *  they paint visually but shouldn't intercept hover. */
    interactive?: boolean;
    bezierCache?: BezierCache;
    style: Style;
    datum: SceneDatum;
    /** Internal gradient used by circular sankey stub bands. */
    _gradient?: {
        x0: number;
        x1: number;
        from: number;
        to: number;
    };
    _pulseIntensity?: number;
    _pulseColor?: string;
    /** Lazily-built Path2D for hit testing; invalidated when pathD changes. */
    _cachedPath2D?: Path2D;
    _cachedPath2DSource?: string;
}
/** Ribbon edge — used by chord */
export interface NetworkRibbonEdge {
    type: "ribbon";
    pathD: string;
    style: Style;
    datum: SceneDatum;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _cachedPath2D?: Path2D;
    _cachedPath2DSource?: string;
}
/** Curved edge — used by tree, cluster */
export interface NetworkCurvedEdge {
    type: "curved";
    pathD: string;
    style: Style;
    datum: SceneDatum;
    _pulseIntensity?: number;
    _pulseColor?: string;
    _cachedPath2D?: Path2D;
    _cachedPath2DSource?: string;
}
export type NetworkSceneNode = NetworkCircleNode | NetworkRectNode | NetworkArcNode;
export type NetworkSceneEdge = NetworkLineEdge | NetworkBezierEdge | NetworkRibbonEdge | NetworkCurvedEdge;
/** Label data for the SVG overlay */
export interface NetworkLabel {
    x: number;
    y: number;
    text: string;
    anchor?: "start" | "middle" | "end";
    baseline?: string;
    fontSize?: number;
    fontWeight?: number | string;
    fill?: string;
    stroke?: string;
    strokeWidth?: number;
    paintOrder?: string;
}
export interface NetworkLayoutPlugin {
    /**
     * Run the layout algorithm. May mutate node/edge positions directly.
     * For bounded data, called once. For streaming, called on topology changes.
     */
    computeLayout(nodes: RealtimeNode[], edges: RealtimeEdge[], config: NetworkPipelineConfig, size: [number, number]): void;
    /**
     * Build scene nodes + labels from the positioned node/edge data.
     */
    buildScene(nodes: RealtimeNode[], edges: RealtimeEdge[], config: NetworkPipelineConfig, size: [number, number]): {
        sceneNodes: NetworkSceneNode[];
        sceneEdges: NetworkSceneEdge[];
        labels: NetworkLabel[];
    };
    /** Whether this layout supports incremental streaming updates */
    supportsStreaming: boolean;
    /** Whether this layout uses hierarchical (tree) input instead of nodes+edges */
    hierarchical: boolean;
    /**
     * Whether this layout drives continuous animation (e.g. orbiting nodes).
     * When true, StreamNetworkFrame keeps its RAF loop alive and calls `tick()` each frame.
     */
    supportsAnimation?: boolean;
    /**
     * Advance one animation frame. Called by StreamNetworkFrame on each RAF tick
     * when `supportsAnimation` is true. Should mutate node positions in-place.
     * Returns true if the scene needs a rebuild (always true for orbit animation).
     */
    tick?: (nodes: RealtimeNode[], edges: RealtimeEdge[], config: NetworkPipelineConfig, size: [number, number], deltaTime: number) => boolean;
}
/** Threshold alerting configuration for streaming network nodes */
export interface ThresholdAlertConfig {
    /** Function that extracts the metric value from a node for threshold comparison */
    metric: (node: RealtimeNode) => number;
    /** Warning threshold — node enters "warning" state when metric >= this value */
    warning?: number;
    /** Critical threshold — node enters "critical" state when metric >= this value */
    critical?: number;
    /** Colors for threshold states */
    warningColor?: string;
    criticalColor?: string;
    /** Whether to pulse nodes that cross a threshold. Default: true */
    pulse?: boolean;
}
export interface NetworkPipelineConfig {
    chartType: NetworkChartType;
    nodeIDAccessor?: string | ((d: Datum) => string);
    sourceAccessor?: string | ((d: Datum) => string);
    targetAccessor?: string | ((d: Datum) => string);
    valueAccessor?: string | ((d: Datum) => number);
    /** Edge ID accessor for removeEdge(edgeId) — enables single-ID edge removal */
    edgeIdAccessor?: string | ((d: Datum) => string);
    childrenAccessor?: string | ((d: Datum) => Datum[]);
    hierarchySum?: string | ((d: Datum) => number);
    orientation?: "horizontal" | "vertical";
    nodeAlign?: "justify" | "left" | "right" | "center";
    nodePaddingRatio?: number;
    nodeWidth?: number;
    edgeSort?: (a: unknown, b: unknown) => number;
    iterations?: number;
    forceStrength?: number;
    padAngle?: number;
    groupWidth?: number;
    sortGroups?: (a: unknown, b: unknown) => number;
    treeOrientation?: "vertical" | "horizontal" | "radial";
    edgeType?: "line" | "curve";
    padding?: number;
    paddingTop?: number;
    tensionConfig?: TensionConfig;
    showParticles?: boolean;
    particleStyle?: ParticleStyle;
    nodeStyle?: (d: Datum) => Datum;
    edgeStyle?: (d: Datum) => Datum;
    nodeLabel?: string | ((d: Datum) => string);
    showLabels?: boolean;
    labelMode?: "leaf" | "parent" | "all";
    colorBy?: string | ((d: Datum) => string | number);
    colorScheme?: string | string[];
    /** Theme categorical palette — used as fallback when colorScheme is not an explicit array */
    themeCategorical?: string[];
    /** Theme-resolved semantic role colors — default fallback before hardcoded hex. See `ThemeSemanticColors` in ./types. */
    themeSemantic?: ThemeSemanticColors;
    edgeColorBy?: "source" | "target" | "gradient" | ((d: Datum) => string);
    edgeOpacity?: number;
    colorByDepth?: boolean;
    nodeSize?: number | string | ((d: Datum) => number);
    nodeSizeRange?: [number, number];
    decay?: DecayConfig;
    pulse?: PulseConfig;
    transition?: TransitionConfig;
    /** Whether to animate elements on first render (nodes scale up, edges fade in) */
    introAnimation?: boolean;
    staleness?: StalenessConfig;
    thresholds?: ThresholdAlertConfig;
    /** Ring arrangement mode: "flat" (all children in one ring), "solar" (one per ring),
     *  "atomic" ([2,8] electron shell), or custom capacities. @default "flat" */
    orbitMode?: "flat" | "solar" | "atomic" | number[];
    /** Ring size divisor per depth. Larger = tighter orbits. @default 2.95 */
    orbitSize?: number | ((node: Datum) => number);
    /** Orbit speed multiplier (higher = faster rotation). @default 0.25 */
    orbitSpeed?: number;
    /** Per-node speed modifier. @default (node) => 1 / (node.depth + 1) */
    orbitRevolution?: (node: Datum) => number;
    /**
     * Built-in revolution style presets:
     * - "locked": children rotate with parent at decreasing speed (default)
     * - "decay": each depth level progressively slower, independent of parent
     * - "alternate": odd-depth rings reverse direction
     * Ignored when `orbitRevolution` is provided.
     * @default "locked"
     */
    orbitRevolutionStyle?: "locked" | "decay" | "alternate";
    /** Vertical squash for elliptical orbits. 1 = circle. @default 1 */
    orbitEccentricity?: number | ((node: Datum) => number);
    /** Show orbital ring ellipses as foreground graphics. @default true */
    orbitShowRings?: boolean;
    /** Enable orbit animation. @default true */
    orbitAnimated?: boolean;
    /** @internal Hierarchy root stashed for tree/treemap/circlepack plugins */
    __hierarchyRoot?: unknown;
    /** @internal Orbit animation state preserved across config updates */
    __orbitState?: unknown;
    /** @internal Previous node positions for warm-start force layout */
    __previousPositions?: Map<string, {
        x: number;
        y: number;
    }>;
    /** When provided, replaces both layout dispatch and scene building.
     *  Receives raw nodes/edges and returns positioned scene primitives. */
    customNetworkLayout?: import("./networkCustomLayout").NetworkCustomLayout;
    /** User-supplied config blob threaded through to NetworkLayoutContext.config. */
    layoutConfig?: object;
}
export interface StreamNetworkFrameProps<T = Datum> {
    chartType: NetworkChartType;
    nodes?: T[];
    edges?: T[] | T;
    /** Hierarchy root (alias for edges when using tree/treemap/circlepack) */
    data?: T;
    initialEdges?: EdgePush[];
    nodeIDAccessor?: string | ((d: T) => string);
    sourceAccessor?: string | ((d: T) => string);
    targetAccessor?: string | ((d: T) => string);
    valueAccessor?: string | ((d: T) => number);
    /** Edge ID accessor for removeEdge(edgeId) single-ID removal */
    edgeIdAccessor?: string | ((d: Datum) => string);
    childrenAccessor?: string | ((d: T) => T[]);
    hierarchySum?: string | ((d: T) => number);
    orientation?: "horizontal" | "vertical";
    nodeAlign?: "justify" | "left" | "right" | "center";
    nodePaddingRatio?: number;
    nodeWidth?: number;
    iterations?: number;
    forceStrength?: number;
    padAngle?: number;
    groupWidth?: number;
    sortGroups?: (a: unknown, b: unknown) => number;
    edgeSort?: (a: unknown, b: unknown) => number;
    treeOrientation?: "vertical" | "horizontal" | "radial";
    edgeType?: "line" | "curve";
    padding?: number;
    paddingTop?: number;
    tensionConfig?: Partial<TensionConfig>;
    showParticles?: boolean;
    particleStyle?: ParticleStyle;
    nodeStyle?: (d: Datum) => Datum;
    edgeStyle?: (d: Datum) => Datum;
    colorBy?: string | ((d: Datum) => string | number);
    colorScheme?: string | string[];
    edgeColorBy?: "source" | "target" | "gradient" | ((d: Datum) => string);
    edgeOpacity?: number;
    colorByDepth?: boolean;
    nodeSize?: number | string | ((d: Datum) => number);
    nodeSizeRange?: [number, number];
    nodeLabel?: string | ((d: Datum) => string);
    showLabels?: boolean;
    labelMode?: "leaf" | "parent" | "all";
    size?: [number, number];
    responsiveWidth?: boolean;
    responsiveHeight?: boolean;
    margin?: {
        top?: number;
        right?: number;
        bottom?: number;
        left?: number;
    };
    className?: string;
    background?: string;
    enableHover?: boolean;
    tooltipContent?: (d: HoverData) => ReactNode;
    customHoverBehavior?: (d: HoverData | null) => void;
    customClickBehavior?: (d: HoverData | null) => void;
    /** Observation callback — emits hover/click events to the ObservationStore and this callback */
    onObservation?: OnObservationCallback;
    /** Chart instance identifier for observation filtering */
    chartId?: string;
    onTopologyChange?: (nodes: RealtimeNode[], edges: RealtimeEdge[]) => void;
    annotations?: Datum[];
    autoPlaceAnnotations?: AutoPlaceAnnotations;
    svgAnnotationRules?: (annotation: Datum, index: number, context: AnnotationContext) => ReactNode;
    legend?: ReactNode | {
        legendGroups: LegendGroup[];
    };
    legendPosition?: "right" | "left" | "top" | "bottom";
    legendLayout?: LegendLayout;
    legendHoverBehavior?: (item: {
        label: string;
    } | null) => void;
    legendClickBehavior?: (item: {
        label: string;
    }) => void;
    legendHighlightedCategory?: string | null;
    legendIsolatedCategories?: Set<string>;
    title?: string | ReactNode;
    foregroundGraphics?: ReactNode;
    backgroundGraphics?: ReactNode;
    decay?: DecayConfig;
    pulse?: PulseConfig;
    transition?: TransitionConfig;
    /** Declarative animation: `true` for defaults (300ms ease-out), or config object.
     *  When enabled, charts animate on first render (intro) and on data change.
     *  Set `{ intro: false }` to disable the intro animation. */
    animate?: AnimateProp;
    staleness?: StalenessConfig;
    thresholds?: ThresholdAlertConfig;
    orbitMode?: "flat" | "solar" | "atomic" | number[];
    orbitSize?: number | ((node: Datum) => number);
    orbitSpeed?: number;
    orbitRevolution?: (node: Datum) => number;
    orbitRevolutionStyle?: "locked" | "decay" | "alternate";
    orbitEccentricity?: number | ((node: Datum) => number);
    orbitShowRings?: boolean;
    orbitAnimated?: boolean;
    /** Render a visually-hidden data table from the scene graph for screen readers */
    accessibleTable?: boolean;
    /** Accessible description overriding the auto-generated aria-label on the chart container */
    description?: string;
    /** Accessible summary rendered as a screen-reader-only note */
    summary?: string;
    /** Replaces network layout + scene dispatch with a user-supplied function.
     *  Receives raw nodes/edges + dimensions/theme, returns positioned scene
     *  primitives. See `semiotic/recipes` for reference layouts (flextree, dagre). */
    customNetworkLayout?: import("./networkCustomLayout").NetworkCustomLayout;
    /** User-supplied config blob threaded through to NetworkLayoutContext.config. */
    layoutConfig?: object;
}
export interface StreamNetworkFrameHandle {
    push(edge: EdgePush): void;
    pushMany(edges: EdgePush[]): void;
    /** Remove a node by ID. Also removes connected edges. */
    removeNode(id: string): boolean;
    /** Remove edges by source+target, or by edge ID when edgeIdAccessor is configured. */
    removeEdge(sourceIdOrEdgeId: string, targetId?: string): boolean;
    /** Update a node's data by ID. Returns previous data. */
    updateNode(id: string, updater: (data: Datum) => Datum): Datum | null;
    /** Update all edges between source+target. Returns array of previous data. */
    updateEdge(sourceId: string, targetId: string, updater: (data: Datum) => Datum): Datum[];
    clear(): void;
    getTopology(): {
        nodes: RealtimeNode[];
        edges: RealtimeEdge[];
    };
    getTopologyDiff(): {
        addedNodes: string[];
        removedNodes: string[];
        addedEdges: string[];
        removedEdges: string[];
    };
    relayout(): void;
    getTension(): number;
}
export type NetworkRendererFn = (ctx: CanvasRenderingContext2D, nodes: NetworkSceneNode[], edges: NetworkSceneEdge[], size: [number, number]) => void;
