import * as _sdcorejs_angular_components_query_builder from '@sdcorejs/angular/components/query-builder';
import * as _angular_core from '@angular/core';
import { Operator, DateRelative, Filter } from '@sdcorejs/utils/models';

/** Field kinds the builder understands. Drives the operator set + value editor. */
type SdQueryBuilderFieldType = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'values';
/** One option for a `values`-type field (enum / lookup). */
interface SdQueryBuilderFieldOption {
    /** Stored value (sent inside the `Filter`). */
    value: any;
    /** Human-readable label shown in the select + view-mode string. */
    display: string;
}
/**
 * One filterable field. `key` matches `Filter.field` (dot-notation allowed);
 * `label` is what the view-mode raw string renders (field token = label).
 */
interface SdQueryBuilderField {
    /** Dot-notation field path — written to `Filter.field`. */
    key: string;
    /** Human label — shown in the field picker AND as the view-mode field token. */
    label: string;
    /** Field type — picks the default operator set + value editor control. */
    type: SdQueryBuilderFieldType;
    /** Material icon shown before the label in the field picker; falls back to `QB_TYPE_ICON[type]` then `'tune'`. */
    icon?: string;
    /** Override the allowed operator set (otherwise `QB_OPERATORS_BY_TYPE[type]`). */
    operators?: Operator[];
    /** Override the starting operator (otherwise `QB_DEFAULT_OPERATOR_BY_TYPE[type]`). */
    defaultOperator?: Operator;
    /** Options for `type: 'values'` — the select list + display-label lookup. */
    values?: SdQueryBuilderFieldOption[];
    /** Label for the `true` branch of a boolean field (default `'Có'`). */
    trueLabel?: string;
    /** Label for the `false` branch of a boolean field (default `'Không'`). */
    falseLabel?: string;
    /** Lower bound for number / date value editors. */
    min?: number | string;
    /** Upper bound for number / date value editors. */
    max?: number | string;
    /** Optional domain guard for field-to-field comparison candidates. */
    compareGroup?: string;
    /** Set false to hide this field from field-to-field comparison. */
    allowFieldCompare?: boolean;
}
interface SdQueryBuilderOption {
    autoId?: string;
    fields: SdQueryBuilderField[];
    mode?: 'edit' | 'view';
    comparisonMode?: QbComparisonMode;
    disabled?: boolean;
    value?: Filter | null;
    filters?: Filter[];
    rootLogic?: 'AND' | 'OR';
    onValueChange?: (value: Filter | null) => void;
    onFiltersChange?: (filters: Filter[]) => void;
    onRootLogicChange?: (logic: 'AND' | 'OR') => void;
}
type QbNode = QbGroup | QbRule;
/** Component-level capability for right-hand operands. */
type QbComparisonMode = 'value-only' | 'value-or-field';
/** Per-rule right-hand operand source. */
type QbValueSource = 'literal' | 'field';
/** A logical group of nodes joined by AND / OR. Maps to `FilterAndOr`. */
interface QbGroup {
    id: string;
    kind: 'group';
    logic: 'AND' | 'OR';
    children: QbNode[];
    /** UI-only: whether this group's "+" dropdown is open. */
    open?: boolean;
}
/** A single `field operator value` condition. Maps to a leaf `Filter`. */
interface QbRule {
    id: string;
    kind: 'rule';
    field?: string;
    operator?: Operator;
    /** Single value, `{ from, to }` for BETWEEN, or an array for IN / NOT_IN. */
    value?: any;
    /** Internal UI state: literal input or a same-type field reference. */
    valueSource?: QbValueSource;
    /** Right-hand field key when `valueSource` is `'field'`. */
    compareField?: string;
}
/** Type guard — narrows a `QbNode` to a `QbGroup`. */
declare function isQbGroup(node: QbNode): node is QbGroup;
type QbTokenKind = 'field' | 'op' | 'value' | 'logic' | 'paren' | 'plain';
/** One piece of the rendered raw query string, tagged for highlight styling. */
interface QbToken {
    text: string;
    kind: QbTokenKind;
}
/** Allowed operators per field type — used when `field.operators` is not set. */
declare const QB_OPERATORS_BY_TYPE: Record<SdQueryBuilderFieldType, Operator[]>;
/** Default operator when a rule is first created for a field. */
declare const QB_DEFAULT_OPERATOR_BY_TYPE: Record<SdQueryBuilderFieldType, Operator>;
/** Operators with no value payload — the value editor is hidden for these. */
declare const QB_NO_DATA_OPERATORS: Operator[];
/** Operators whose value is an array — the value editor offers multi-select. */
declare const QB_MULTI_OPERATORS: Operator[];
/** Operators allowed for `field` — explicit override wins, else the per-type set. */
declare function qbAllowedOperators(field: SdQueryBuilderField | undefined): Operator[];
/** Starting operator for a new rule on `field` — falls back to the per-type default. */
declare function qbDefaultOperator(field: SdQueryBuilderField | undefined): Operator | undefined;
/** True when `op` is NULL / NOT_NULL (no value editor). */
declare function qbIsNoDataOperator(op: Operator | undefined): boolean;
/** True when `op` is IN / NOT_IN (array value). */
declare function qbIsMultiOperator(op: Operator | undefined): boolean;
/** True when the operator accepts one right-hand operand, including a field reference. */
declare function qbSupportsFieldCompareOperator(op: Operator | undefined): boolean;
/**
 * Icon fallback per field type when `SdQueryBuilderField.icon` is not set.
 * Mirrors query-bar's `SD_QUERY_TYPE_ICON` so the two components read consistently,
 * but kept local so query-builder has no dependency on the query-bar package.
 */
declare const QB_TYPE_ICON: Record<SdQueryBuilderFieldType, string>;
/**
 * Icon shown before a field in the field picker / selected trigger.
 * Priority: `field.icon` → `QB_TYPE_ICON[field.type]` → `'tune'` (default, like query-bar).
 */
declare function qbFieldIcon(field: SdQueryBuilderField | undefined): string;
/** Next stable node id with the given prefix. */
declare function qbId(prefix?: string): string;
/** Build a fresh rule node (optionally pre-filled). */
declare function qbNewRule(field?: string, operator?: Operator, value?: any, valueSource?: QbValueSource, compareField?: string): QbRule;
/** Build a fresh group node. */
declare function qbNewGroup(logic?: 'AND' | 'OR', children?: QbNode[]): QbGroup;
/** Offset unit for a relative date — re-exported from the utils `DateRelative` model. */
type SdQbRelativeUnit = DateRelative['unit'];
/** Offset direction for a relative date — re-exported from the utils `DateRelative` model. */
type SdQbRelativeDirection = DateRelative['direction'];
/** Sentinel held as a rule value (and emitted as `data`) for the "today" date mode. */
declare const QB_TODAY = "TODAY";
/** The `'TODAY'` sentinel type (matches the utils `date-today` data literal). */
type QbToday = typeof QB_TODAY;
/** Date value editor mode for a date/datetime rule (derived from the rule value). */
type QbDateMode = 'absolute' | 'now' | 'relative';
/** Type guard — narrows a rule value to a utils `DateRelative` (offset spec). */
declare const qbIsRelativeDate: (v: any) => v is DateRelative;
/** Type guard — narrows a rule value to the `'TODAY'` sentinel ("now"/today mode). */
declare function qbIsToday(v: any): v is QbToday;
/** Starting relative value when a rule first switches to "relative" mode. */
declare function qbDefaultRelative(): DateRelative;
/** One date-mode option — carries a Material icon shown in the dropdown + selected trigger. */
interface QbDateModeOption {
    value: QbDateMode;
    display: string;
    /** Material icon name (outlined set). */
    icon: string;
}
/** Stable option list for the date-mode select (module ref — never reallocated). */
declare const QB_DATE_MODES: ReadonlyArray<QbDateModeOption>;
/** One value-source option for field-to-field comparison UI. */
interface QbValueSourceOption {
    value: QbValueSource;
    display: string;
    /** Material icon name (outlined set). */
    icon: string;
}
/** Stable option list for choosing between a literal value and another field. */
declare const QB_VALUE_SOURCE_OPTIONS: ReadonlyArray<QbValueSourceOption>;
/** Stable combined direction×unit option list (token `'unit:direction'`). */
declare const QB_RELATIVE_UNIT_OPTIONS: ReadonlyArray<{
    value: string;
    display: string;
}>;
/** Shared empty option array — stable ref for fallbacks (avoids per-call allocation). */
declare const QB_EMPTY_OPTIONS: SdQueryBuilderFieldOption[];

/**
 * Visual filter / rule builder. Compose nested AND / OR groups of
 * `field operator value` conditions; emits the canonical `Filter` (root is a
 * `FilterAndOr` tree) via `[(value)]`, plus a flat `[(filters)]` mirror of the
 * root group's direct children. `mode="view"` renders a read-only SQL-ish raw
 * string with highlighted operators + values.
 */
declare class SdQueryBuilder {
    #private;
    /** Main option object. Prefer this API for new usage; individual inputs stay as a migration bridge. */
    readonly option: _angular_core.InputSignal<SdQueryBuilderOption | undefined>;
    /** Filterable fields — each declares a `type` that drives the operator set + value editor. */
    readonly fields: _angular_core.InputSignal<SdQueryBuilderField[]>;
    /** `'edit'` (default) = interactive tree · `'view'` = read-only raw-query string. */
    readonly mode: _angular_core.InputSignal<"edit" | "view">;
    /** `value-only` = literal operands only · `value-or-field` = each rule may compare against another field. */
    readonly comparisonMode: _angular_core.InputSignal<QbComparisonMode>;
    /** Disable all editing controls. */
    readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
    /** Prefix for `data-autoid` on inner controls (E2E selectors). */
    readonly autoId: _angular_core.InputSignal<string | undefined>;
    /** Canonical output — the root `FilterAndOr` tree, or `null` when empty. `[(value)]`. */
    readonly value: _angular_core.ModelSignal<Filter | null>;
    /** Convenience mirror — the root group's direct children. `[(filters)]`. */
    readonly filters: _angular_core.ModelSignal<Filter[]>;
    /** Root group's logical connector. `[(rootLogic)]`. */
    readonly rootLogic: _angular_core.ModelSignal<"AND" | "OR">;
    readonly tree: _angular_core.Signal<QbGroup>;
    /** `field.key` → field, for fast lookup from a rule. */
    readonly resolvedFields: _angular_core.Signal<SdQueryBuilderField[]>;
    readonly resolvedMode: _angular_core.Signal<"edit" | "view">;
    readonly resolvedComparisonMode: _angular_core.Signal<QbComparisonMode>;
    readonly resolvedDisabled: _angular_core.Signal<boolean>;
    readonly resolvedAutoId: _angular_core.Signal<string | undefined>;
    readonly fieldByKey: _angular_core.Signal<Record<string, SdQueryBuilderField>>;
    /** Stable option list for the date-mode select. */
    readonly dateModes: readonly _sdcorejs_angular_components_query_builder.QbDateModeOption[];
    /** Stable option list for the literal-vs-field operand select. */
    readonly valueSourceOptions: readonly _sdcorejs_angular_components_query_builder.QbValueSourceOption[];
    /** Stable combined unit×direction option list for the relative select. */
    readonly relativeUnitOptions: readonly {
        value: string;
        display: string;
    }[];
    /** View-mode token stream — recomputed from the emitted value. */
    readonly tokens: _angular_core.Signal<QbToken[]>;
    readonly isView: _angular_core.Signal<boolean>;
    /** Expose the type-guard to the template. */
    readonly isGroup: typeof isQbGroup;
    /** Resolve the leading icon for a field (own `icon` → per-type → `'tune'`) — used by the field picker. */
    readonly fieldIcon: typeof qbFieldIcon;
    constructor();
    /** Switch a group's AND/OR connector and re-emit. No-op when disabled or unchanged. */
    setGroupLogic(group: QbGroup, logic: 'AND' | 'OR'): void;
    /** Open this group's "+" menu (closing any other open one). UI-only — does not emit. */
    toggleDropdown(group: QbGroup, event: Event): void;
    closeAllDropdowns(): void;
    /** Append a blank rule to `group`. */
    addRule(group: QbGroup): void;
    /** Append a nested sub-group (seeded with one blank rule) to `group`. */
    addGroup(group: QbGroup): void;
    /** Remove the child at `index` from `parent` (a rule or a whole sub-group). */
    removeNode(parent: QbGroup, index: number): void;
    /**
     * Point `rule` at a new field. Resets operator to the field's default and the value
     * to that operator's empty shape — the old operator/value rarely fit the new type.
     *
     * @param rule - the rule being edited.
     * @param key - the chosen field key (from the field picker). Swap-only: a null / undefined
     *   key is a no-op — the field can be changed but never cleared (issue #2).
     */
    setField(rule: QbRule, key: any): void;
    /** Change `rule`'s operator and reshape its value to fit the new operator (array / range / none). */
    setOperator(rule: QbRule, op: Operator | undefined): void;
    /** Set a single-value rule's value (coercing numeric fields to `number`). */
    setScalar(rule: QbRule, raw: any): void;
    /** Set the lower bound of a BETWEEN rule's `{ from, to }` value. */
    setBetweenFrom(rule: QbRule, raw: any): void;
    /** Set the upper bound of a BETWEEN rule's `{ from, to }` value. */
    setBetweenTo(rule: QbRule, raw: any): void;
    setValueSource(rule: QbRule, source: QbValueSource): void;
    setCompareField(rule: QbRule, key: any): void;
    /** The field metadata for a rule's current `field` key (or undefined if unset). */
    fieldOf(rule: QbRule): SdQueryBuilderField | undefined;
    /** Operators allowed for a rule, derived from its field's type / override. */
    allowedOperators(rule: QbRule): Operator[];
    /** Whether to render the operator picker — hidden when only one operator is allowed. */
    showOperatorSelector(rule: QbRule): boolean;
    compareFields(rule: QbRule): SdQueryBuilderField[];
    canCompareWithField(rule: QbRule): boolean;
    showValueSourceSelector(rule: QbRule): boolean;
    valueSourceOf(rule: QbRule): QbValueSource;
    isFieldSource(rule: QbRule): boolean;
    /** True for NULL / NOT_NULL — the template then renders no value editor. */
    isNoData(op: Operator | undefined): boolean;
    /** True for IN / NOT_IN — the template then renders a multi-select value editor. */
    isMulti(op: Operator | undefined): boolean;
    /** `[true/false]` option list for a boolean field's value select (stable reference). */
    booleanItems(field: SdQueryBuilderField): SdQueryBuilderFieldOption[];
    /** Current date-value mode of a rule, derived from its value (no separate state). */
    dateMode(rule: QbRule): QbDateMode;
    /** Switch a date/datetime rule's value mode, reseeding the value for the new mode. */
    setDateMode(rule: QbRule, mode: QbDateMode): void;
    /** Read the offset amount of a relative rule (default 1). */
    relativeAmount(rule: QbRule): number;
    /** Set the offset amount (clamped to an integer >= 1). */
    setRelativeAmount(rule: QbRule, raw: any): void;
    /** Read the `'unit:direction'` token of a relative rule (default `'day:previous'`). */
    relativeUnitDirValue(rule: QbRule): string;
    /** Set the offset unit + direction from a `'unit:direction'` token. */
    setRelativeUnitDir(rule: QbRule, token: string): void;
    /** Build a `data-autoid` for an inner control under this builder's `autoId` prefix. */
    autoIdFor(suffix: string): string;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdQueryBuilder, never>;
    static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdQueryBuilder, "sd-query-builder", never, { "option": { "alias": "option"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "comparisonMode": { "alias": "comparisonMode"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "rootLogic": { "alias": "rootLogic"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "filters": "filtersChange"; "rootLogic": "rootLogicChange"; }, never, never, true, never>;
}

/**
 * Map the internal builder tree to the public `Filter` (the root is always a
 * `FilterAndOr`). Rules missing field / operator / value — and empty nested
 * groups — are dropped so the result is always a valid `Filter`.
 *
 * @param group - the editable tree's root group.
 * @returns the canonical nested `Filter`, or `null` when no complete rule survives.
 */
declare function treeToFilter(group: QbGroup): Filter | null;
/**
 * Inverse of {@link treeToFilter} — rebuild the editable tree from a `Filter` so a
 * consumer can seed `[value]`. A non-group (bare) filter is wrapped in an AND root;
 * `null` yields an empty AND root.
 *
 * @param filter - a `Filter` (group or leaf), or `null` / `undefined` for an empty tree.
 * @returns a fresh root `QbGroup` mirroring the filter's structure.
 */
declare function filterToTree(filter: Filter | null | undefined): QbGroup;
/**
 * Render a `Filter` to a SQL-ish token stream for view mode. Field tokens use the
 * matching field's `label`; operators map to SQL syntax (`= != like between is null …`);
 * `and` / `or` are lowercase; nested multi-child groups are wrapped in parentheses.
 * Returns a token stream (not a string) so the template can wrap each piece in a
 * highlight `<span>` keyed by `QbToken.kind`.
 *
 * @param filter - the `Filter` to render, or `null` / `undefined`.
 * @param fields - field metadata, used to resolve each field key to its display label + value formatting.
 * @returns the ordered tokens, or `[]` when `filter` is empty.
 */
declare function filterToTokens(filter: Filter | null | undefined, fields: SdQueryBuilderField[]): QbToken[];

export { QB_DATE_MODES, QB_DEFAULT_OPERATOR_BY_TYPE, QB_EMPTY_OPTIONS, QB_MULTI_OPERATORS, QB_NO_DATA_OPERATORS, QB_OPERATORS_BY_TYPE, QB_RELATIVE_UNIT_OPTIONS, QB_TODAY, QB_TYPE_ICON, QB_VALUE_SOURCE_OPTIONS, SdQueryBuilder, filterToTokens, filterToTree, isQbGroup, qbAllowedOperators, qbDefaultOperator, qbDefaultRelative, qbFieldIcon, qbId, qbIsMultiOperator, qbIsNoDataOperator, qbIsRelativeDate, qbIsToday, qbNewGroup, qbNewRule, qbSupportsFieldCompareOperator, treeToFilter };
export type { QbComparisonMode, QbDateMode, QbDateModeOption, QbGroup, QbNode, QbRule, QbToday, QbToken, QbTokenKind, QbValueSource, QbValueSourceOption, SdQbRelativeDirection, SdQbRelativeUnit, SdQueryBuilderField, SdQueryBuilderFieldOption, SdQueryBuilderFieldType, SdQueryBuilderOption };
