/**
 * Pure, immutable canvas-edit transforms + the agent client-tool factory
 * shared by the Form Builder cockpit (`FormBuilderResourceComponent`) and
 * Component Studio's Form Builder tab (`ComponentStudioDashboardComponent`).
 *
 * ──────────────────────────────────────────────────────────────────────────
 * WHY THIS FILE EXISTS
 * Both surfaces edit the SAME {@link FormCanvasModel} via the SAME lifecycle
 * mutations (add/remove field, relabel, toggle required, set span, reorder,
 * add/remove/rename section). The granular VOICE-EDIT client-tool suite a
 * realtime co-agent uses to drive the canvas must therefore be defined ONCE
 * and reused — otherwise the two surfaces drift. The transforms here are the
 * correctness backbone (this is where the unit tests live); the per-component
 * wiring is a thin adapter that supplies "read the current canvas" + "apply a
 * new canvas" callbacks.
 *
 * ──────────────────────────────────────────────────────────────────────────
 * 🔒 SAFETY BOUNDARY
 * EVERY transform in this file is a REVERSIBLE edit to the in-memory canvas
 * DEFINITION only. Nothing here saves, publishes, persists, activates an
 * override, or deletes a whole form/Component — those are destructive /
 * irreversible operations the user must confirm in the UI, and they are
 * intentionally NOT exposed as agent tools. The agent can rearrange the
 * canvas freely; committing that canvas to the database stays a human action.
 * Do NOT add a Save / Publish / DeleteForm tool to {@link buildCanvasEditClientTools}.
 * ──────────────────────────────────────────────────────────────────────────
 */
import { type FormCanvasElement, type FormCanvasModel, type FormCanvasSection } from './form-canvas-model';
/** A typed agent client-tool, matching the shape NavigationService expects. */
export interface CanvasEditClientTool {
    Name: string;
    Description: string;
    ParameterSchema: Record<string, unknown>;
    Handler: (params: Record<string, unknown>) => Promise<CanvasEditToolResult>;
}
/** Uniform result envelope every canvas-edit tool returns. */
export interface CanvasEditToolResult {
    Success: boolean;
    Data?: unknown;
    ErrorMessage?: string;
}
/** A successful transform plus a short human-readable note (for the agent). */
export interface CanvasTransformResult {
    canvas: FormCanvasModel;
    note: string;
}
/** Find an element by id across all sections. Returns null when absent. */
export declare function findElement(canvas: FormCanvasModel, elementId: string): FormCanvasElement | null;
/** Find a section by id. Returns null when absent. */
export declare function findSection(canvas: FormCanvasModel, sectionId: string): FormCanvasSection | null;
/** Distinct field names currently placed on the canvas, in display order. */
export declare function collectFieldNames(canvas: FormCanvasModel): string[];
/** Find the section that contains the given element id. Null when absent. */
export declare function findSectionOfElement(canvas: FormCanvasModel, elementId: string): FormCanvasSection | null;
/**
 * Best display label for an element — the explicit label override, else the
 * field name, else the element type. Used so the context the agent sees (and
 * the tolerant resolvers below) can talk about elements by a human label, not
 * just opaque ids.
 */
export declare function elementDisplayLabel(el: FormCanvasElement): string;
/**
 * Resolve an element by id OR by a human label (display-label / field name),
 * case-insensitively. Tries exact id → exact label (case-insensitive) →
 * partial-contains on the label. Returns null on no match so the caller can
 * emit a tolerant "no such field" error listing what IS available. A voice
 * co-agent rarely has the synthetic element id to hand — it heard "the email
 * field" — so accepting the label keeps the granular tools usable by voice.
 */
export declare function resolveElement(canvas: FormCanvasModel, idOrLabel: string): FormCanvasElement | null;
/**
 * Resolve a section by id OR by its title, case-insensitively (exact id →
 * exact title → partial-contains). Same rationale as {@link resolveElement}.
 */
export declare function resolveSection(canvas: FormCanvasModel, idOrTitle: string): FormCanvasSection | null;
/**
 * Return a NEW canvas with a shallow patch applied to the element identified
 * by `elementId`. Sections/elements not touched are reused by reference; the
 * containing section and the target element are reconstructed immutably.
 * No-op (returns the same canvas reference) when the element is absent.
 */
export declare function updateElementInCanvas(canvas: FormCanvasModel, elementId: string, patch: Partial<FormCanvasElement>): FormCanvasModel;
/** Return a NEW canvas with the given element removed from its section. */
export declare function removeElementFromCanvas(canvas: FormCanvasModel, elementId: string): FormCanvasModel;
/**
 * Return a NEW canvas with a freshly-created field element appended to the
 * target section. The new element id is supplied by the caller (so the host
 * can use its own id generator) — pure functions don't reach for randomness.
 * No-op when the section is absent.
 */
export declare function addFieldToCanvas(canvas: FormCanvasModel, sectionId: string, fieldName: string, newElementId: string): FormCanvasModel;
/**
 * Return a NEW canvas with the element identified by `elementId` MOVED to the
 * end of the target section (or to `index` within it, clamped). No-op (same
 * reference) when the element or the target section is absent, or when the
 * element is already the only thing where it'd land in the same spot. Moving
 * within the same section acts as a reposition.
 */
export declare function moveElementToSection(canvas: FormCanvasModel, elementId: string, targetSectionId: string, index?: number): FormCanvasModel;
/**
 * Return a NEW canvas with a DUPLICATE of `elementId` inserted immediately
 * after the original, in the same section. The clone's id is caller-supplied
 * (purity). No-op when the source element is absent.
 */
export declare function duplicateElementInCanvas(canvas: FormCanvasModel, elementId: string, newElementId: string): FormCanvasModel;
/** Return a NEW canvas with a shallow patch applied to one section. */
export declare function updateSectionInCanvas(canvas: FormCanvasModel, sectionId: string, patch: Partial<Omit<FormCanvasSection, 'id' | 'elements'>>): FormCanvasModel;
/** Return a NEW canvas with the given section removed. */
export declare function removeSectionFromCanvas(canvas: FormCanvasModel, sectionId: string): FormCanvasModel;
/**
 * Return a NEW canvas with a new empty section inserted at `index` (clamped
 * to [0, sections.length]; an out-of-range or omitted index appends). The new
 * section's id is caller-supplied for the same purity reason as fields.
 */
export declare function addSectionToCanvas(canvas: FormCanvasModel, newSectionId: string, title?: string, index?: number): FormCanvasModel;
/**
 * Return a NEW canvas with the target section's elements reordered to match
 * `orderedElementIds`. The provided ids must be exactly the section's current
 * element ids (a permutation) — otherwise the transform refuses and returns
 * the same canvas reference, so a bad reorder can't silently drop elements.
 */
export declare function reorderSectionElements(canvas: FormCanvasModel, sectionId: string, orderedElementIds: ReadonlyArray<string>): FormCanvasModel;
/**
 * Return a NEW canvas with its sections reordered to match `orderedSectionIds`.
 * The ids must be exactly a permutation of the canvas's current section ids —
 * otherwise the transform refuses (same reference), so a bad reorder can't
 * silently drop a section.
 */
export declare function reorderSections(canvas: FormCanvasModel, orderedSectionIds: ReadonlyArray<string>): FormCanvasModel;
/**
 * Move a single section to a new 0-based position (clamped to range). Thin
 * convenience over {@link reorderSections} for the "move THIS section up/to
 * the top" voice command. No-op when the section is absent.
 */
export declare function moveSectionToIndex(canvas: FormCanvasModel, sectionId: string, index: number): FormCanvasModel;
/**
 * Coerce an arbitrary numeric span request to the canvas's supported set.
 * The {@link FormCanvasElement} grid span is `1 | 2` (half / full width); any
 * value >= 2 collapses to full-width, anything else to half-width. Keeps the
 * tool tolerant of an agent passing "make it span 12" loosely.
 */
export declare function normalizeSpan(requested: number): 1 | 2;
/** The element `type` values the canvas understands, for SetFieldType. */
export declare const CANVAS_ELEMENT_TYPES: ReadonlyArray<FormCanvasElement['type']>;
/** Coerce a loose `type` request to a valid {@link FormCanvasElement} type, or null. */
export declare function normalizeElementType(requested: string): FormCanvasElement['type'] | null;
/** Cap on every name/summary list published to the agent. */
export declare const CANVAS_CONTEXT_LIST_CAP = 25;
/** One section, summarised for the agent: id, title, field-count, element ids. */
export interface SectionSummary {
    id: string;
    title: string;
    collapsible: boolean;
    columns: 1 | 2;
    elementCount: number;
    fieldCount: number;
}
/** One element, summarised for the agent so it can target it by id or label. */
export interface ElementSummary {
    id: string;
    type: FormCanvasElement['type'];
    label: string;
    fieldName: string | null;
    sectionId: string;
    required: boolean;
    span: 1 | 2;
}
/**
 * The full canvas-state slice both surfaces publish so the agent can target
 * the right element/section and know what's placeable — WITHOUT a tool
 * round-trip. Everything here is derived purely from the canvas + the optional
 * curated field list; the host layers in its own dirty-flag / pane-mode /
 * variant / validation context around this.
 *
 * Lists are bounded to {@link CANVAS_CONTEXT_LIST_CAP}; each capped list gets a
 * companion `*Truncated` flag + a true `*Count` so the agent knows there's more.
 */
export interface CanvasStateSummary {
    EntityName: string;
    FormTitle: string | null;
    SectionCount: number;
    ElementCount: number;
    FieldCount: number;
    /** Section list (bounded). */
    Sections: SectionSummary[];
    SectionsTruncated: boolean;
    /** Placed elements (bounded), each addressable by id or label. */
    Elements: ElementSummary[];
    ElementsTruncated: boolean;
    /** Distinct field names already on the canvas (bounded). */
    PlacedFieldNames: string[];
    /** Curated entity field names NOT yet placed — the AddField candidate set (bounded). */
    AvailableFieldNames: string[];
    AvailableFieldNamesTruncated: boolean;
    AvailableFieldNameCount: number;
    /** Resolved display info for the currently-selected element (or null). */
    SelectedElement: ElementSummary | null;
    /** Resolved display info for the currently-selected section (or null). */
    SelectedSection: SectionSummary | null;
}
/**
 * Build the bounded {@link CanvasStateSummary} for the agent.
 *
 * @param canvas             the live canvas (null → an "empty" summary).
 * @param schemaFieldNames   ALL curated entity field names (for AvailableFieldNames).
 * @param selectedElementId  the host's current element selection, if any.
 * @param selectedSectionId  the host's current section selection, if any.
 */
export declare function buildCanvasStateSummary(canvas: FormCanvasModel | null, schemaFieldNames: ReadonlyArray<string>, selectedElementId: string | null, selectedSectionId: string | null): CanvasStateSummary | null;
/**
 * Host adapter the tool factory needs: how to read the live canvas, how to
 * apply a transformed canvas back (the host owns dirty-tracking / code
 * regeneration / change detection), how to mint ids, plus the four
 * center-pane / preview navigation actions. Pane actions are optional —
 * Component Studio routes them through its tab system rather than a
 * `SetCenterPaneMode`, so it omits them.
 */
export interface CanvasEditHost {
    /** Current canvas, or null when no form is loaded. */
    GetCanvas(): FormCanvasModel | null;
    /** Apply the transformed canvas (host marks dirty + regenerates code). */
    ApplyCanvas(next: FormCanvasModel): void;
    /** Mint a stable element id for a newly added field. */
    NewElementId(): string;
    /** Mint a stable section id for a newly added section. */
    NewSectionId(): string;
    /** Optional: switch the center pane to the live preview (+ optional record). */
    PreviewForm?(recordId?: string): void;
    /** Optional: switch the center pane to the code view. */
    ViewFormCode?(): void;
    /** Optional: switch the center pane to the layout/canvas view. */
    ViewFormLayout?(): void;
}
/**
 * Build the granular, reversible canvas-edit client-tool suite. Both Form
 * Builder and Component Studio register the returned array (alongside their
 * existing wholesale `UpdateForm` tool) so a realtime co-agent can voice-edit
 * the form one field/section at a time.
 *
 * Each transform tool: reads the live canvas, applies a pure transform, and
 * (when the transform actually changed something) pushes the result back
 * through the host. Tools that target a specific element/section return a
 * descriptive `ErrorMessage` when the id isn't found — so the agent gets a
 * clear "no such field" instead of a silent no-op.
 */
export declare function buildCanvasEditClientTools(host: CanvasEditHost): CanvasEditClientTool[];
//# sourceMappingURL=canvas-edit-transforms.d.ts.map