import type { Effect } from 'effect';
/**
 * Public types for the generic Tree UI primitive.
 *
 * Everything in this module is intentionally business-agnostic:
 *   - no HTTP, no CEL, no form-field knowledge
 *   - no judgement of "what is a leaf" — `getChildren` returning `undefined`
 *     is the only way to mark a terminal node
 *   - selection / filter are orthogonal: filter never mutates `modelValue`
 *
 * The component is the data plane; visuals come from slots.
 */
export type NodeKey = string;
export type SelectionMode = 'none' | 'single' | 'multi';
/**
 * Cascade behaviour for `multi` selection mode. Ignored for `single` / `none`.
 *
 *   - `independent`  — clicking a node toggles only that node
 *   - `cascade-down` — toggling a parent toggles all selectable descendants
 *   - `cascade-both` — `cascade-down` + parents reflect descendant state via
 *                      `selected`/`indeterminate` flags exposed to the
 *                      `#node` slot. The `modelValue` array still only
 *                      contains literally-clicked descendant keys.
 */
export type CascadeMode = 'independent' | 'cascade-down' | 'cascade-both';
/**
 * Children semantics. See README/design doc — required to be locked down:
 *
 *   - `undefined` — node is a terminal leaf, no children, do not call loader
 *   - `[]`        — no inline children, ask `loadChildren`
 *   - `Node[]`    — use these synchronously, do not call loader
 */
export type GetChildren<Node> = (node: Node) => Node[] | undefined;
/**
 * Async loader for a single node's children. Returns an Effect so that the
 * caller (e.g. the future form-field layer) can compose errors and contexts
 * without the component locking the error channel.
 */
export type LoadChildren<Node, E = unknown> = (node: Node) => Effect.Effect<Node[], E>;
/**
 * Slot prop bundle for `#node` — passed for every rendered row's left side.
 *
 * Selection / indeterminate are pre-computed by the component so that the
 * consumer can bind straight to a `<Checkbox>` / `<Radio>` (the component
 * already renders the toggle itself; these are exposed for visual feedback
 * inside the slot body, e.g. greying the label).
 */
export interface NodeSlotProps<Node> {
    node: Node;
    depth: number;
    expanded: boolean;
    loading: boolean;
    selected: boolean;
    indeterminate: boolean;
    tree: TreeHandle<Node>;
}
export interface ActionsSlotProps<Node> {
    node: Node;
    depth: number;
    tree: TreeHandle<Node>;
}
export interface ErrorSlotProps<Node> {
    node: Node;
    error: unknown;
    retry: () => void;
}
export interface LoadingChildrenSlotProps<Node> {
    node: Node;
}
export interface SelectedPaneSlotProps<Node> {
    selected: Node[];
    tree: TreeHandle<Node>;
}
/**
 * Drop context handed to `canDrop`. `beforeKey === null` means "append to end
 * of `intoParent`'s children". `intoParent === null` is a root-level drop.
 */
export interface DropContext<Node> {
    drag: {
        node: Node;
        fromParent: Node | null;
        fromIndex: number;
    };
    drop: {
        intoParent: Node | null;
        beforeKey: NodeKey | null;
    };
}
export interface MoveEventPayload {
    key: NodeKey;
    fromParentKey: NodeKey | null;
    fromIndex: number;
    toParentKey: NodeKey | null;
    toIndex: number;
}
/**
 * Exposed handle. Surface area mirrors the design doc one-to-one.
 *
 * In controlled mode (`v-model:roots`) mutation methods emit
 * `update:roots` with a freshly-spliced array; in uncontrolled mode they
 * mutate the internal copy directly.
 */
export interface TreeHandle<Node> {
    insert: (parentKey: NodeKey | null, node: Node, index?: number) => void;
    remove: (key: NodeKey) => void;
    move: (key: NodeKey, newParentKey: NodeKey | null, index: number) => void;
    update: (key: NodeKey, patch: Partial<Node>) => void;
    expand: (key: NodeKey) => void;
    collapse: (key: NodeKey) => void;
    select: (key: NodeKey) => void;
    deselect: (key: NodeKey) => void;
    invalidate: (key: NodeKey) => void;
    retry: (key: NodeKey) => void;
    findPath: (key: NodeKey) => Node[] | null;
    snapshot: () => {
        roots: Node[];
        selected: NodeKey[];
        expanded: NodeKey[];
    };
}
