type TreeNodeValue = Record<string, unknown> | string | number | boolean | null;
type TreeNodeValidId = string | number;
interface TreeLeafNode<TValue extends TreeNodeValue | undefined = undefined, TId extends TreeNodeValidId = string> {
    id: TId;
    parentId: TId;
    children: [];
    value?: TValue | undefined;
}
interface TreeParentNode<TValue extends TreeNodeValue | undefined = undefined, TId extends TreeNodeValidId = string> {
    id: TId;
    parentId: TId | null;
    children: TreeNode<TValue, TId>[];
    value?: TValue | undefined;
}
interface TreeRootNode<TValue extends TreeNodeValue | undefined = undefined, TId extends TreeNodeValidId = string> {
    id: TId;
    parentId: null;
    children: TreeNode<TValue, TId>[];
    value?: TValue | undefined;
}
type TreeNode<TValue extends TreeNodeValue | undefined = undefined, TId extends TreeNodeValidId = string> = TreeRootNode<TValue, TId> | TreeParentNode<TValue, TId> | TreeLeafNode<TValue, TId>;

type TreeMapperResult<TValue extends TreeNodeValue | undefined, TKey extends string = string> = {
    success: true;
    treeNodes: TreeNode<TValue, TKey>[];
} | {
    success: false;
    message: string;
    issues: TreeMapperIssue[];
};
type TreeMapperIssue = {
    message: string;
};

type FlatTreeWsParams = {
    separator: string;
};
type FlatTreeWsUniqueKey = string;
type FlatTreeWsMap<TValue extends TreeNodeValue | undefined, TKey extends FlatTreeWsUniqueKey = string> = Map<TKey, TValue>;
type FlatTreeWsRecord<TValue extends TreeNodeValue | undefined, TKey extends FlatTreeWsUniqueKey = string> = Record<TKey, TValue>;
type FlatTreeWs<TValue extends TreeNodeValue | undefined, TKey extends FlatTreeWsUniqueKey = string> = FlatTreeWsMap<TValue, TKey> | FlatTreeWsRecord<TValue, TKey>;
declare class FlatTreeWsMapper<TValue extends TreeNodeValue, TKey extends string = string> {
    toTreeNodes: (data: FlatTreeWs<TValue, TKey>, params: FlatTreeWsParams) => TreeMapperResult<TValue, TKey>;
    /**
     * @throws Error
     */
    toTreeNodesOrThrow: (data: FlatTreeWs<TValue, TKey>, params: FlatTreeWsParams) => TreeNode<TValue, TKey>[];
    /**
     * Will convert a tree of nodes to a flat tree.
     */
    fromTreeNodesOrThrow: <TId extends string = string>(treeNodes: TreeNode<TValue, TId>[], params: {
        method: "breadth-first";
    }) => FlatTreeWsMap<TValue, TKey>;
}

type TreeSearchFindParams = {
    includeChildren?: boolean;
    reverse?: boolean;
};
type NativeNodeSearchKeys = [
    key: 'id' | 'parentId',
    equality: '===',
    value: string
];
type TreeNodeOptionalChildren<TValue extends TreeNodeValue | undefined, TKey extends string | number = string> = TreeNode<TValue, TKey> & {
    children?: TreeNode<TValue, TKey>;
};
/**
 * Depth-First Search (DFS) algorithm for tree structures. It uses a stack rather
 * than recursion in order to support deeply nested trees without call-stack overflows.
 * It is well suited for exploring a branch of a data structure in depth and
 * usually preferred when memory usage is a concern or when the data
 * structure has many nodes with few levels.
 *
 * @see https://hackernoon.com/a-beginners-guide-to-bfs-and-dfs-in-javascript
 */
declare class DfsTreeSearch<TValue extends TreeNodeValue | undefined, TKey extends string | number = string> {
    private readonly treeNodes;
    constructor(treeNodes: TreeNode<TValue, TKey>[]);
    /**
     * Find first matching node in the tree. The `reverse` parameter can be used
     * to traverse the tree in reverse order.
     */
    findOne: (idOrConditionOrFn: TKey | NativeNodeSearchKeys | ((treeNode: TreeNode<TValue, TKey>) => boolean), params?: TreeSearchFindParams) => TreeNodeOptionalChildren<TValue, TKey> | undefined;
}

declare class Tree<TValue extends TreeNodeValue | undefined, TKey extends string = string> {
    protected readonly treeNodes: TreeNode<TValue, TKey>[];
    constructor(treeNodes: TreeNode<TValue, TKey>[]);
    getTreeNodes: () => TreeNode<TValue, TKey>[];
}

export { DfsTreeSearch, type FlatTreeWs, FlatTreeWsMapper, Tree, type TreeLeafNode, type TreeNode, type TreeNodeValue, type TreeParentNode, type TreeRootNode };
