import * as _angular_core from '@angular/core';
import { Signal, TemplateRef } from '@angular/core';
import { SdButton } from '@sdcorejs/angular/components/button';
import { SdUnwrapSignal, MaterialIconFontSet } from '@sdcorejs/angular/utilities/models';
import { Color } from '@sdcorejs/utils/models';

type SdTreeDataSource<TItem = any> = TItem[] | Signal<TItem[]> | (() => TItem[] | Promise<TItem[]>);
type SdTreeLoadType = 'static' | 'lazy';
type SdTreeOption<T = any> = SdTreeStaticOption<T> | SdTreeLazyOption<T>;
type SdTreeItem<T = any> = SdTreeItemStatic<T> | SdTreeItemLazy<T>;
type SdTreeItemByLoadType<T = any, TLoadType extends SdTreeLoadType = SdTreeLoadType> = TLoadType extends 'lazy' ? SdTreeItemLazy<T> : SdTreeItemStatic<T>;
interface SdTreeItemBase<T = any> {
    /** Stable node id used for expansion, selection, filtering ancestry, and auto-id generation. */
    id: string;
    /** Text shown by the default tree row. Custom templates can still read `item` / `treeItem`. */
    label: string;
    /**
     * Optional node icon override.
     * - Branch without `icon`: tree renders the default folder icon (`folder` / `folder_open`).
     * - Leaf without `icon`: tree renders no icon.
     * This replaces the old `leafIcon` split. One field is enough because each node decides its own icon.
     */
    icon?: string | null;
    /** Consumer payload. Commands, selection callbacks, and `$implicit` template context receive this value. */
    data: T;
    /** Initial expansion state for this node. Component state wins after the user toggles. */
    expanded?: boolean;
}
interface SdTreeItemStatic<T = any> extends SdTreeItemBase<T> {
    /** Static-mode children. Lazy mode does not use this field. */
    children?: SdTreeItemStatic<T>[];
    /** `hasChildren` belongs to lazy mode only; static mode derives branches from `children`. */
    hasChildren?: never;
}
interface SdTreeItemLazy<T = any> extends SdTreeItemBase<T> {
    /** Lazy-mode hint. Set `false` for known leaf nodes that do not need `onExpandChildren`. */
    hasChildren?: boolean;
    /** `children` belongs to static mode only; lazy loaded children are cached inside the component. */
    children?: never;
}
interface SdTreeBaseOption {
    maxDepth?: number;
    indentSize?: number;
}
interface SdTreeStaticOption<T = any> extends SdTreeBaseOption {
    loadType: 'static';
    /** Expand all (`true`), none (`false`), or root levels where `level < number`. */
    defaultExpanded?: boolean | number;
}
interface SdTreeLazyOption<T = any> extends SdTreeBaseOption {
    loadType: 'lazy';
    /**
     * Called once when a lazy node is first expanded. Return wrapped `SdTreeItemLazy<T>` children,
     * not raw data, so each child has a stable id/label/icon contract.
     */
    onExpandChildren: (item: SdTreeItemLazy<T>) => Promise<SdTreeItemLazy<T>[]> | SdTreeItemLazy<T>[];
}
interface SdTreeCommand<T = any> {
    key: string;
    title: string | ((item: T) => string);
    icon?: string | ((item: T) => string | undefined | null);
    color?: Color;
    fontSet?: MaterialIconFontSet;
    disabled?: boolean | ((item: T) => boolean);
    hidden?: boolean | ((item: T) => boolean);
    click: (item: T) => void;
}
interface SdTreeSelectorOption<T = any> {
    visible?: boolean;
    actions?: SdTreeSelectionAction<T>[];
    message?: string | ((selectedItems: T[]) => string);
    disabled?: (item: T, selectedItems: T[]) => boolean;
}
interface SdTreeSelectionAction<T = any> {
    icon?: string;
    fontSet?: SdUnwrapSignal<SdButton['fontSet']>;
    tooltip?: SdUnwrapSignal<SdButton['tooltip']>;
    title?: SdUnwrapSignal<SdButton['title']>;
    color?: SdUnwrapSignal<SdButton['color']>;
    type?: SdUnwrapSignal<SdButton['type']>;
    hidden?: boolean | ((selectedItems: T[]) => boolean);
    click: (selectedItems: T[]) => void;
}
interface SdTreeComponentOptionBase<T = any, TItem extends SdTreeItem<T> = SdTreeItem<T>> {
    autoId?: string | null;
    /** Root nodes can be an array, a signal, a sync loader, or an async loader. Call `reload()` to rerun loader sources. */
    items: SdTreeDataSource<TItem>;
    selectedItems?: T[] | null;
    selector?: SdTreeSelectorOption<T> | null;
    commands?: SdTreeCommand<T>[] | null;
    itemTemplate?: SdTreeItemTemplate<T> | null;
    selectable?: boolean;
    onSelectedItemsChange?: (items: T[]) => void;
    onSelect?: (event: SdTreeSelectionEvent<T>) => void;
    onExpand?: (event: SdTreeToggleEvent<T>) => void;
    onCollapse?: (event: SdTreeToggleEvent<T>) => void;
}
interface SdTreeStaticComponentOption<T = any> extends SdTreeComponentOptionBase<T, SdTreeItemStatic<T>> {
    /** Static tree is the default when `tree` is omitted. */
    tree?: SdTreeStaticOption<T>;
}
interface SdTreeLazyComponentOption<T = any> extends SdTreeComponentOptionBase<T, SdTreeItemLazy<T>> {
    tree: SdTreeLazyOption<T>;
}
type SdTreeComponentOption<T = any> = SdTreeStaticComponentOption<T> | SdTreeLazyComponentOption<T>;
interface SdTreeNode<T = any> {
    /** Wrapped tree item containing id/label/icon/data plus mode-specific tree metadata. */
    treeItem: SdTreeItem<T>;
    /** Raw consumer payload. Kept as a shortcut because most callbacks operate on data, not wrapper metadata. */
    data: T;
    id: string;
    label: string;
    level: number;
    parent: SdTreeNode<T> | null;
    children: SdTreeNode<T>[];
    hasChildren: boolean;
    isExpanded: boolean;
    isLoading: boolean;
}
interface SdTreeItemContext<T = any> {
    $implicit: T;
    item: T;
    treeItem: SdTreeItem<T>;
    node: SdTreeNode<T>;
    level: number;
    expanded: boolean;
    selected: boolean;
    loading: boolean;
    hasChildren: boolean;
    isLeaf: boolean;
    toggle: () => void;
    select: () => void;
}
type SdTreeItemTemplate<T = any> = TemplateRef<SdTreeItemContext<T>>;
interface SdTreeSelectionEvent<T = any> {
    item: T;
    selected: boolean;
    selectedItems: T[];
}
interface SdTreeToggleEvent<T = any> {
    item: T;
    expanded: boolean;
    node: SdTreeNode<T>;
}

declare class SdTreeItemDefDirective<T = any> {
    static ngTemplateContextGuard<T>(_dir: SdTreeItemDefDirective<T>, ctx: unknown): ctx is SdTreeItemContext<T>;
    readonly templateRef: TemplateRef<SdTreeItemContext<T>>;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdTreeItemDefDirective<any>, never>;
    static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SdTreeItemDefDirective<any>, "[sdTreeItemDef]", never, {}, {}, never, never, true, never>;
}

type SdTreeAutoIdPart = 'row' | 'toggle' | 'checkbox' | 'icon' | 'label' | 'command';
interface SdTreeNodeAutoIds {
    row?: string;
    toggle?: string;
    checkbox?: string;
    icon?: string;
    label?: string;
    command?: string;
}
interface SdTreeViewCommand<T = any> {
    key: string;
    command: SdTreeCommand<T>;
    title: string;
    icon: string;
    color: SdTreeCommand<T>['color'];
    fontSet: SdTreeCommand<T>['fontSet'];
    disabled: boolean;
    autoId?: string;
    defaultColor: boolean;
}
interface SdTreeViewNode<T = any> extends SdTreeNode<T> {
    icon?: string;
    selected: boolean;
    selectionDisabled: boolean;
    toggleDisabled: boolean;
    toggleLabel: string;
    ariaExpanded: boolean | null;
    autoIds: SdTreeNodeAutoIds;
    commands: SdTreeViewCommand<T>[];
    context: SdTreeItemContext<T>;
}
interface SdTreeSelectionActionView<T = any> {
    action: SdTreeSelectionAction<T>;
    autoId: string | null;
}
declare class SdTree<T = any> {
    #private;
    readonly autoIdInput: _angular_core.InputSignal<string | null | undefined>;
    readonly option: _angular_core.InputSignal<SdTreeComponentOption<T> | undefined>;
    /** Migration bridge. New usage should put the data source in `option.items`. */
    readonly items: _angular_core.InputSignal<SdTreeDataSource<SdTreeItem<T>> | undefined>;
    /** Migration bridge. New usage should put static/lazy config in `option.tree`. */
    readonly tree: _angular_core.InputSignal<SdTreeOption<T> | undefined>;
    readonly selectedItemsInput: _angular_core.InputSignal<T[] | null | undefined>;
    readonly commands: _angular_core.InputSignal<SdTreeCommand<T>[] | null | undefined>;
    readonly selectable: _angular_core.InputSignalWithTransform<boolean, unknown>;
    readonly selector: _angular_core.InputSignal<SdTreeSelectorOption<T> | null | undefined>;
    readonly itemTemplate: _angular_core.InputSignal<TemplateRef<SdTreeItemContext<T>> | null | undefined>;
    readonly selectedItemsChange: _angular_core.OutputEmitterRef<T[]>;
    readonly selectChange: _angular_core.OutputEmitterRef<SdTreeSelectionEvent<T>>;
    readonly expandChange: _angular_core.OutputEmitterRef<SdTreeToggleEvent<T>>;
    readonly collapseChange: _angular_core.OutputEmitterRef<SdTreeToggleEvent<T>>;
    readonly itemDef: _angular_core.Signal<SdTreeItemDefDirective<any> | undefined>;
    readonly resolvedItemsSource: _angular_core.Signal<SdTreeDataSource<SdTreeItem<T>>>;
    readonly resolvedTree: _angular_core.Signal<SdTreeOption<T>>;
    readonly resolvedSelector: _angular_core.Signal<SdTreeSelectorOption<T> | null | undefined>;
    readonly resolvedCommands: _angular_core.Signal<SdTreeCommand<T>[]>;
    readonly resolvedSelectable: _angular_core.Signal<boolean>;
    readonly autoId: _angular_core.Signal<string | undefined>;
    readonly resolvedItemTemplate: _angular_core.Signal<TemplateRef<SdTreeItemContext<T>> | undefined>;
    readonly indentSize: _angular_core.Signal<number>;
    readonly normalizedFilterText: _angular_core.Signal<string>;
    readonly selectionVisible: _angular_core.Signal<boolean>;
    readonly selectedIdSet: _angular_core.Signal<Set<string>>;
    readonly rootNodes: _angular_core.Signal<SdTreeNode<T>[]>;
    readonly visibleNodes: _angular_core.Signal<SdTreeNode<T>[]>;
    readonly selectedItems: _angular_core.Signal<T[]>;
    readonly selectedCount: _angular_core.Signal<number>;
    readonly selectionMessage: _angular_core.Signal<string>;
    readonly visibleSelectionActions: _angular_core.Signal<SdTreeSelectionAction<T>[]>;
    readonly selectionActionViews: _angular_core.Signal<SdTreeSelectionActionView<T>[]>;
    readonly clearSelectionAutoId: _angular_core.Signal<string | null>;
    /**
     * Template-facing row model. Expensive/variable values are resolved once per
     * signal recomputation so the HTML does not call helper methods for every CD pass.
     */
    readonly visibleViewNodes: _angular_core.Signal<SdTreeViewNode<T>[]>;
    readonly trackByNode: (_index: number, node: SdTreeNode<T>) => string;
    constructor();
    reload(): void;
    filter(searchText: string | undefined | null): void;
    isSelected(node: SdTreeNode<T>): boolean;
    nodeIcon(node: SdTreeNode<T>): string | undefined;
    visibleCommands(node: SdTreeNode<T>): SdTreeCommand<T>[];
    isSelectionDisabled(node: SdTreeNode<T>): boolean;
    commandTitle(command: SdTreeCommand<T>, item: T): string;
    commandIcon(command: SdTreeCommand<T>, item: T): string;
    isCommandDisabled(command: SdTreeCommand<T>, item: T): boolean;
    toggle(node: SdTreeNode<T>, event?: Event): Promise<void>;
    toggleSelection(node: SdTreeNode<T>, event?: Event): void;
    clearSelection(): void;
    onSelectionAction(action: SdTreeSelectionAction<T>): void;
    createContext(node: SdTreeNode<T>): SdTreeItemContext<T>;
    nodeAutoId(node: SdTreeNode<T>, part: SdTreeAutoIdPart): string | undefined;
    commandAutoId(node: SdTreeNode<T>, command: SdTreeCommand<T>): string | undefined;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdTree<any>, never>;
    static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdTree<any>, "sd-tree", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "option": { "alias": "option"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "tree": { "alias": "tree"; "required": false; "isSignal": true; }; "selectedItemsInput": { "alias": "selectedItems"; "required": false; "isSignal": true; }; "commands": { "alias": "commands"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "selector": { "alias": "selector"; "required": false; "isSignal": true; }; "itemTemplate": { "alias": "itemTemplate"; "required": false; "isSignal": true; }; }, { "selectedItemsChange": "selectedItemsChange"; "selectChange": "selectChange"; "expandChange": "expandChange"; "collapseChange": "collapseChange"; }, ["itemDef"], never, true, never>;
}

export { SdTree, SdTreeItemDefDirective };
export type { SdTreeAutoIdPart, SdTreeBaseOption, SdTreeCommand, SdTreeComponentOption, SdTreeComponentOptionBase, SdTreeDataSource, SdTreeItem, SdTreeItemBase, SdTreeItemByLoadType, SdTreeItemContext, SdTreeItemLazy, SdTreeItemStatic, SdTreeItemTemplate, SdTreeLazyComponentOption, SdTreeLazyOption, SdTreeLoadType, SdTreeNode, SdTreeNodeAutoIds, SdTreeOption, SdTreeSelectionAction, SdTreeSelectionActionView, SdTreeSelectionEvent, SdTreeSelectorOption, SdTreeStaticComponentOption, SdTreeStaticOption, SdTreeToggleEvent, SdTreeViewCommand, SdTreeViewNode };
