import { components } from '@shotstack/schemas';

/**
 * Payload passed to button click handlers.
 */
declare interface ButtonClickPayload {
    /** Current playback position in seconds */
    position: number;
    /** Currently selected clip, if any */
    selectedClip: {
        trackIndex: number;
        clipIndex: number;
    } | null;
}

export declare class Canvas {
    private static extensionsRegistered;
    private viewportSize;
    private readonly edit;
    private viewportContainer?;
    private editBackground?;
    private viewportMask?;
    private container?;
    private background?;
    private timeline?;
    private uiController;
    private alignmentGuides;
    private minZoom;
    private maxZoom;
    private currentZoom;
    private onTickBound;
    private onBackgroundClickBound;
    private onWheelBound;
    private canvasRoot;
    constructor(edit: Edit);
    load(): Promise<void>;
    private setupTouchHandling;
    private onWheel;
    centerEdit(): void;
    zoomToFit(padding?: number): void;
    resize(): void;
    setZoom(zoom: number): void;
    getZoom(): number;
    /**
     * Sync overlay container and toolbar positions after content transforms change.
     * Single point of update for all position-dependent UI elements.
     */
    private syncContentTransforms;
    /**
     * Subscribe to Edit events for visual synchronization.
     * Canvas reacts to these events to update PIXI visuals.
     */
    private subscribeToEditEvents;
    private onPlayerAddedToTrack;
    private onPlayerMovedBetweenTracks;
    private onPlayerRemovedFromTrack;
    private onTrackContainerRemoved;
    private onViewportSizeChanged;
    private onViewportNeedsZoomToFit;
    private registerExtensions;
    private configureApplication;
    private onTick;
    private configureStage;
    private onBackgroundClick;
    dispose(): void;
}

declare type Clip = components["schemas"]["Clip"];

declare type ClipLocation = {
    trackIndex: number;
    clipIndex: number;
};

/**
 * Reference to a clip from the document (source of truth).
 * Contains original timing values like "auto", "end", and alias references.
 * Used in public SDK events so consumers see the document state.
 */
declare type ClipReference = ClipLocation & {
    clip: Clip;
};

export declare class Controls {
    private edit;
    private seekDistance;
    private seekDistanceLarge;
    private frameTime;
    constructor(timeline: Edit);
    load(): Promise<void>;
    private shouldIgnoreKeyboardEvent;
    private handleKeyDown;
    private handleKeyUp;
}

declare type Destination = components["schemas"]["Destinations"];

export declare class Edit {
    private static readonly MAX_HISTORY_SIZE;
    private document;
    private backgroundColor;
    private tracks;
    playbackTime: Seconds;
    totalDuration: Seconds;
    isPlaying: boolean;
    private get clips();
    private internalEvents;
    events: ReadonlyEventEmitter<EditEventMap>;
    private canvas;
    private timingManager;
    private lumaMaskController;
    private playerReconciler;
    private outputSettings;
    private selectionManager;
    private commandHistory;
    private commandIndex;
    private commandQueue;
    private clipsToDispose;
    private clipErrors;
    private playerByClipId;
    private lumaContentRelations;
    private fontMetadata;
    private isBatchingEvents;
    private syncCorrectionCount;
    private isExporting;
    private lastResolved;
    /**
     * Create an Edit instance from a template configuration.
     */
    constructor(template: Edit_2);
    /**
     * Load the edit session.
     */
    load(): Promise<void>;
    /**
     * Initialize runtime from the document.
     */
    private initializeFromDocument;
    play(): void;
    pause(): void;
    seek(target: Seconds): void;
    stop(): void;
    /**
     * Reload the edit with a new configuration (hot-reload).
     */
    loadEdit(edit: Edit_2): Promise<void>;
    private loadSoundtrack;
    getEdit(): Edit_2;
    addClip(trackIdx: number, clip: Clip): void | Promise<void>;
    getClip(trackIdx: number, clipIdx: number): Clip | null;
    /**
     * Clear the error for a deleted clip and shift indices for remaining errors.
     */
    private clearClipErrorAndShift;
    deleteClip(trackIdx: number, clipIdx: number): Promise<void>;
    splitClip(trackIndex: number, clipIndex: number, splitTime: number): Promise<void>;
    addTrack(trackIdx: number, track: Track): Promise<void>;
    getTrack(trackIdx: number): Track | null;
    deleteTrack(trackIdx: number): void;
    undo(): Promise<void>;
    redo(): Promise<void>;
    /**
     * Add a command to history without executing it.
     */
    private addCommandToHistory;
    updateClip(trackIdx: number, clipIdx: number, updates: Partial<Clip>): Promise<void>;
    /**
     * Handle command result - only add to history if successful.
     */
    private handleCommandResult;
    /**
     * Detects merge field placeholders in the raw edit before substitution.
     */
    private detectMergeFieldBindings;
    /**
     * Recursively walks an object to find merge field placeholders.
     */
    private detectBindingsInObject;
    /**
     * Checks if edit has structural changes requiring full reload.
     *
     * TODO: Expand granular path to handle more cases:
     * - Clip add/remove: Use existing addClip()/deleteClip() commands
     * - Soundtrack changes: Add/remove AudioPlayer via commands
     * - Font changes: Load new fonts incrementally
     * - Merge field changes: Re-resolve affected clips
     */
    private hasStructuralChanges;
    /**
     * Transfers existing clip IDs from the current document to the new edit configuration.
     */
    private preserveClipIdsForGranularUpdate;
    /**
     * Applies granular changes without full reload.
     * @param newEdit - The new edit configuration
     * @param oldTracks - The old tracks (captured before document update)
     * @param oldOutput - The old output settings (captured before document update)
     */
    private applyGranularChanges;
    private queueDisposeClip;
    /**
     * Remove fonts from timeline.fonts that are no longer referenced by any clip.
     */
    private cleanupUnusedFonts;
    /**
     * Extract the filename (without extension) from a font URL.
     */
    private extractFilenameFromUrl;
    private disposeClip;
    private unloadClipAssets;
    private movePlayerToTrackContainer;
    private addPlayer;
    setOutputSize(width: number, height: number): Promise<void>;
    setOutputFps(fps: number): Promise<void>;
    getOutputFps(): number;
    setOutputFormat(format: string): Promise<void>;
    getOutputFormat(): string;
    setOutputDestinations(destinations: Destination[]): Promise<void>;
    getOutputDestinations(): Destination[];
    setOutputResolution(resolution: string): Promise<void>;
    getOutputResolution(): string | undefined;
    setOutputAspectRatio(aspectRatio: string): Promise<void>;
    getOutputAspectRatio(): string | undefined;
    setTimelineBackground(color: string): Promise<void>;
    private setTimelineBackgroundInternal;
    getTimelineBackground(): string;
    /**
     * Find the content clip that best matches a luma (by temporal overlap).
     */
    private findBestContentMatch;
    private setupIntentListeners;
}

declare type Edit_2 = components["schemas"]["Edit"];

/** Configuration for defining an edit - the structure passed to EditSession */
export declare type EditConfig = Edit_2;

declare const EditEvent: {
    readonly PlaybackPlay: "playback:play";
    readonly PlaybackPause: "playback:pause";
    readonly TimelineUpdated: "timeline:updated";
    readonly TimelineBackgroundChanged: "timeline:backgroundChanged";
    readonly ClipAdded: "clip:added";
    readonly ClipSplit: "clip:split";
    readonly ClipSelected: "clip:selected";
    readonly ClipUpdated: "clip:updated";
    readonly ClipDeleted: "clip:deleted";
    readonly ClipRestored: "clip:restored";
    readonly ClipCopied: "clip:copied";
    readonly ClipLoadFailed: "clip:loadFailed";
    readonly ClipUnresolved: "clip:unresolved";
    readonly SelectionCleared: "selection:cleared";
    readonly EditChanged: "edit:changed";
    readonly EditUndo: "edit:undo";
    readonly EditRedo: "edit:redo";
    readonly TrackAdded: "track:added";
    readonly TrackRemoved: "track:removed";
    readonly DurationChanged: "duration:changed";
    readonly OutputResized: "output:resized";
    readonly OutputResolutionChanged: "output:resolutionChanged";
    readonly OutputAspectRatioChanged: "output:aspectRatioChanged";
    readonly OutputFpsChanged: "output:fpsChanged";
    readonly OutputFormatChanged: "output:formatChanged";
    readonly OutputDestinationsChanged: "output:destinationsChanged";
    readonly MergeFieldChanged: "mergefield:changed";
    readonly LumaAttached: "luma:attached";
    readonly LumaDetached: "luma:detached";
};

declare type EditEventMap = {
    [EditEvent.PlaybackPlay]: void;
    [EditEvent.PlaybackPause]: void;
    /** Contains the document (source of truth) with original timing values like "auto", "end" */
    [EditEvent.TimelineUpdated]: {
        current: Edit_2;
    };
    [EditEvent.TimelineBackgroundChanged]: {
        color: string;
    };
    [EditEvent.ClipAdded]: ClipLocation;
    [EditEvent.ClipSplit]: {
        trackIndex: number;
        originalClipIndex: number;
        newClipIndex: number;
    };
    [EditEvent.ClipSelected]: ClipReference;
    [EditEvent.ClipUpdated]: {
        previous: ClipReference;
        current: ClipReference;
    };
    [EditEvent.ClipDeleted]: ClipLocation;
    [EditEvent.ClipRestored]: ClipLocation;
    [EditEvent.ClipCopied]: ClipLocation;
    [EditEvent.ClipLoadFailed]: ClipLocation & {
        error: string;
        assetType: string;
    };
    [EditEvent.ClipUnresolved]: ClipLocation & {
        assetType: string;
        clipId: string;
    };
    [EditEvent.SelectionCleared]: void;
    [EditEvent.EditChanged]: {
        source: string;
        timestamp: number;
    };
    [EditEvent.EditUndo]: {
        command: string;
    };
    [EditEvent.EditRedo]: {
        command: string;
    };
    [EditEvent.TrackAdded]: {
        trackIndex: number;
        totalTracks: number;
    };
    [EditEvent.TrackRemoved]: {
        trackIndex: number;
    };
    [EditEvent.DurationChanged]: {
        duration: number;
    };
    [EditEvent.OutputResized]: {
        width: number;
        height: number;
    };
    [EditEvent.OutputResolutionChanged]: {
        resolution: Output["resolution"];
    };
    [EditEvent.OutputAspectRatioChanged]: {
        aspectRatio: Output["aspectRatio"];
    };
    [EditEvent.OutputFpsChanged]: {
        fps: number;
    };
    [EditEvent.OutputFormatChanged]: {
        format: Output["format"];
    };
    [EditEvent.OutputDestinationsChanged]: {
        destinations: Destination[];
    };
    [EditEvent.MergeFieldChanged]: {
        fields: MergeField[];
    };
    [EditEvent.LumaAttached]: ClipLocation & {
        lumaSrc: string;
        lumaClipIndex: number;
    };
    [EditEvent.LumaDetached]: ClipLocation;
};

declare type EventPayloadMap<TPayload = any> = Record<string, TPayload>;

declare type Listener<TPayload = any> = (payload: TPayload) => void;

/**
 * Merge field types for the Shotstack Studio SDK.
 *
 * Merge fields allow dynamic content substitution using {{ FIELD_NAME }} syntax.
 * Values are replaced at render time, enabling template-based video generation.
 */
/**
 * A merge field definition used throughout the SDK.
 */
declare interface MergeField {
    /** Field identifier (uppercase convention: MY_FIELD) */
    name: string;
    /** Default value used for preview when no runtime value is provided */
    defaultValue: string;
    /** Optional description for UI display */
    description?: string;
}

declare type Output = components["schemas"]["Output"];

/**
 * Read-only view of an EventEmitter that only exposes subscription methods.
 * Used as the public `events` type on Edit to prevent consumers from emitting events.
 */
declare interface ReadonlyEventEmitter<TEventPayloadMap extends EventPayloadMap> {
    on<K extends keyof TEventPayloadMap>(name: K, listener: Listener<TEventPayloadMap[K]>): () => void;
    once<K extends keyof TEventPayloadMap>(name: K, listener: Listener<TEventPayloadMap[K]>): () => void;
    off<K extends keyof TEventPayloadMap>(name: K, listener: Listener<TEventPayloadMap[K]>): void;
}

/**
 * A number representing time in seconds.
 * Used at API/configuration boundaries where users specify timing.
 */
declare type Seconds = number & {
    readonly [SecondsSymbol]: typeof SecondsSymbol;
};

declare const SecondsSymbol: unique symbol;

export declare class Timeline {
    private readonly edit;
    readonly element: HTMLElement;
    private readonly container;
    private readonly stateManager;
    private clipRenderers;
    private thumbnailGenerator;
    private mediaThumbnailRenderer;
    private toolbar;
    private rulerTracksWrapper;
    private ruler;
    private trackList;
    private playhead;
    private playheadGhost;
    private feedbackLayer;
    private interactionController;
    private animationFrameId;
    private isRenderLoopActive;
    private lastFrameTime;
    private isInteracting;
    private isLoaded;
    private thumbnailRenderPending;
    private readonly handleTimelineUpdated;
    private readonly handlePlaybackPlay;
    private readonly handlePlaybackPause;
    private readonly handleClipSelected;
    private readonly handleClipLoadFailed;
    private readonly handleClipUpdated;
    private readonly handleRulerMouseMove;
    constructor(edit: Edit, container: HTMLElement);
    /** Initialize and mount the timeline */
    load(): Promise<void>;
    /** Clean up and unmount the timeline */
    dispose(): void;
    /**
     * Pre-compute AI asset numbers for all clips.
     */
    private computeAiAssetNumbers;
    private setupEventListeners;
    private removeEventListeners;
    /** Start continuous render loop (during playback or interaction) */
    private startRenderLoop;
    /** Stop continuous render loop */
    private stopRenderLoop;
    /** Animation frame callback */
    private tick;
    /** Request a single render (used when idle and data changes) */
    private requestRender;
    private buildComponents;
    private disposeComponents;
    zoomIn(): void;
    zoomOut(): void;
}

/**
 * Configuration for a toolbar button.
 */
export declare interface ToolbarButtonConfig {
    /** Unique identifier for the button (used in event names) */
    id: string;
    /** SVG icon markup */
    icon: string;
    /** Tooltip text shown on hover */
    tooltip: string;
    /** Whether to show a divider before this button */
    dividerBefore?: boolean;
}

declare type Track = components["schemas"]["Track"];

/**
 * Controller for managing UI elements (toolbars, utilities) separately from Canvas.
 *
 * This enables:
 * - Pure preview mode (Canvas without UI)
 * - Optional UI element loading
 *
 * @example
 * ```typescript
 * const ui = UIController.create(edit, canvas, { mergeFields: true });
 * ui.registerButton({ id: "text", icon: "...", tooltip: "Add Text" });
 * ```
 */
export declare class UIController {
    private toolbars;
    private utilities;
    private canvasOverlays;
    private container;
    private canvas;
    private isDisposed;
    /** Whether merge fields UI is enabled (Variables panel, autocomplete) */
    readonly mergeFieldsEnabled: boolean;
    /** Whether selection handles are enabled for drag/resize/rotate */
    private readonly selectionHandlesEnabled;
    /** Maximum total pixels for resolution picker (undefined = unlimited) */
    private readonly maxPixels?;
    private clipToolbar;
    private toolbarMode;
    private currentAssetType;
    private currentTrackIndex;
    private currentClipIndex;
    private onKeyDownBound;
    private modeButtonHandlers;
    private buttonRegistry;
    private buttonEvents;
    private assetToolbar;
    private canvasToolbar;
    private lastAutoAssetX;
    private lastAutoAssetY;
    private lastAutoCanvasX;
    private lastAutoCanvasY;
    /**
     * Create a UIController with all standard toolbars pre-registered.
     * This is the recommended way to create a UIController for most use cases.
     *
     * @param edit - The Edit instance
     * @param canvas - The Canvas instance
     * @param options - Configuration options
     * @returns A fully configured UIController
     *
     * @example
     * ```typescript
     * const ui = UIController.create(edit, canvas, { mergeFields: true });
     * ui.registerButton({ id: "text", icon: "...", tooltip: "Add Text" });
     * ui.on("button:text", ({ position }) => { ... });
     * ```
     */
    static create(edit: Edit, canvas: Canvas, options?: UIControllerOptions): UIController;
    /**
     * Create a minimal UIController without pre-registered toolbars.
     * Use this when you only need custom buttons without default toolbars.
     *
     * @param edit - The Edit instance
     * @param canvas - Optional Canvas instance
     * @returns A minimal UIController ready for custom configuration
     *
     * @example
     * ```typescript
     * const ui = UIController.minimal(edit, canvas);
     * ui.registerButton({ id: "text", icon: "...", tooltip: "Add Text" });
     * ```
     */
    static minimal(edit: Edit, canvas?: Canvas): UIController;
    /**
     * Private constructor - use UIController.create() or UIController.minimal() instead.
     */
    private constructor();
    private readonly edit;
    /**
     * Subscribe to edit events. Called by factory methods.
     */
    private subscribeToEvents;
    /**
     * Register all standard toolbars. Called by create() factory.
     */
    private registerStandardToolbars;
    /**
     * Mount all registered UI components to a container.
     * Should be called after all registrations are complete.
     *
     * @param container - The DOM element to mount UI components into
     */
    mount(container: HTMLElement): void;
    /**
     * Position a sidebar toolbar at autoX/autoY, applying the user's drag offset if present.
     */
    private applySidebarPosition;
    /**
     * Dispose all registered UI components and clean up event listeners.
     */
    dispose(): void;
    /**
     * Register a toolbar button.
     * Buttons appear in the left toolbar and trigger events when clicked.
     *
     * @example
     * ```typescript
     * ui.registerButton({
     *   id: "text",
     *   icon: `<svg>...</svg>`,
     *   tooltip: "Add Text"
     * });
     *
     * ui.on("button:text", ({ position }) => {
     *   edit.addTrack(0, { clips: [{ ... }] });
     * });
     * ```
     *
     * @param config - Button configuration
     * @returns this (for chaining)
     */
    registerButton(config: ToolbarButtonConfig): this;
    /**
     * Unregister a toolbar button.
     *
     * @param id - Button ID to remove
     * @returns this (for chaining)
     */
    unregisterButton(id: string): this;
    /**
     * Subscribe to a button click event.
     *
     * @example
     * ```typescript
     * ui.on("button:text", ({ position, selectedClip }) => {
     *   console.log("Text button clicked at position:", position);
     * });
     * ```
     *
     * @param event - Event name in format `button:${buttonId}`
     * @param handler - Callback function
     * @returns Unsubscribe function
     */
    on<K extends `button:${string}`>(event: K, handler: (payload: ButtonClickPayload) => void): () => void;
    /**
     * Set the toolbar mode and update visibility accordingly.
     * @param mode - "asset" shows asset-specific toolbar, "clip" shows ClipToolbar
     */
    private setToolbarMode;
    /**
     * Hide all registered toolbars.
     */
    private hideAllToolbars;
    /**
     * Update toolbar visibility based on current mode and selection.
     */
    private updateToolbarVisibility;
    /**
     * Check if any toolbar is currently visible (clip is selected).
     */
    private hasVisibleToolbar;
    /**
     * Check if an input element is focused (to avoid intercepting typing).
     */
    private isInputFocused;
    /**
     * Handle backtick (`) key to toggle between asset and clip mode.
     * Backtick is the video editor convention for mode/view toggling (Premiere, After Effects).
     */
    private onKeyDown;
    private onClipSelected;
    private onSelectionCleared;
}

/**
 * Options for UIController configuration.
 */
export declare interface UIControllerOptions {
    /** Enable selection handles for drag/resize/rotate interactions. Default: true */
    selectionHandles?: boolean;
    /** Enable merge fields UI (Variables panel, autocomplete). Default: false (vanilla video editor) */
    mergeFields?: boolean;
    /** Maximum total pixels allowed for resolution picker input. Omit for unlimited. */
    maxPixels?: number;
}

export declare const VERSION: string;

export declare class VideoExporter {
    private readonly edit;
    private readonly canvas;
    private readonly app;
    private isExporting;
    private videoProcessor;
    private audioProcessor;
    private progressUI;
    private exportCommand;
    constructor(edit: Edit, canvas: Canvas);
    export(filename?: string, fps?: number): Promise<void>;
    private processFrames;
    private handleKeyDown;
    dispose(): void;
    private prepareConfig;
    private saveEditState;
    private restoreEditState;
    private isVideoPlayer;
}

export { }
