import { ICaptionWord } from '@openvideo/core';
import { BaseClip } from './base-clip';
import { IClip } from './iclip';
import { CaptionJSON, ICaptionWordAnimation } from '../json-serialization';
import { Application, Texture } from 'pixi.js';
import { BaseSpriteEvents } from '../sprite/base-sprite';
export interface ITextBoxStyle {
    style?: "tiktok" | "none";
    textAlign?: "left" | "center" | "right" | "";
    maxLines?: number;
    borderRadius?: number;
    horizontalPadding?: number;
    verticalPadding?: number;
}
export interface ICaptionStyle {
    fontSize?: number;
    fontFamily?: string;
    fontWeight?: string | number;
    fontStyle?: string;
    color?: ICaptionOpts["color"];
    align?: ICaptionOpts["align"];
    textCase?: ICaptionOpts["textCase"];
    verticalAlign?: ICaptionOpts["verticalAlign"];
    wordsPerLine?: ICaptionOpts["wordsPerLine"];
    stroke?: {
        color: string | number;
        width: number;
    };
    shadow?: {
        color?: string | number;
        alpha?: number;
        blur?: number;
        offsetX?: number;
        offsetY?: number;
    };
    wordAnimation?: ICaptionWordAnimation;
    textBoxStyle?: ITextBoxStyle;
}
export interface ICaptionEvents extends BaseSpriteEvents {
    propsChange: Partial<{
        left: number;
        top: number;
        width: number;
        height: number;
        angle: number;
        zIndex: number;
        opacity: number;
        volume: number;
        text: string;
        words: ICaptionWord[];
        color: ICaptionOpts["color"];
        align: ICaptionOpts["align"];
        textCase: ICaptionOpts["textCase"];
        stroke: ICaptionOpts["stroke"];
        shadow: ICaptionOpts["shadow"];
        caption: ICaptionOpts["caption"];
        wordsPerLine: ICaptionOpts["wordsPerLine"];
        textBoxStyle: ITextBoxStyle;
    }>;
}
export interface ICaptionOpts {
    /**
     * Font size in pixels
     * @default 30
     */
    fontSize?: number;
    /**
     * Font family
     * @default 'Arial'
     */
    fontFamily?: string;
    fontUrl?: string;
    /**
     * Font weight (e.g., 'normal', 'bold', '400', '700')
     * @default 'normal'
     */
    fontWeight?: string | number;
    /**
     * Font style (e.g., 'normal', 'italic')
     * @default 'normal'
     */
    fontStyle?: string;
    /**
     * Text color (hex string, color name, or gradient object)
     * @default '#ffffff'
     */
    color?: string | number | {
        type: "gradient";
        x0: number;
        y0: number;
        x1: number;
        y1: number;
        colors: Array<{
            ratio: number;
            color: string | number;
        }>;
    };
    /**
     * Caption data (matches caption object in JSON)
     */
    caption?: {
        words?: Array<{
            text: string;
            from: number;
            to: number;
            isKeyWord?: boolean;
            paragraphIndex?: number;
        }>;
        colors?: {
            appeared?: string;
            active?: string;
            activeFill?: string;
            background?: string;
            keyword?: string;
        };
        preserveKeywordColor?: boolean;
        positioning?: {
            videoWidth?: number;
            videoHeight?: number;
            bottomOffset?: number;
        };
        wordAnimation?: ICaptionWordAnimation;
        textBoxStyle?: ITextBoxStyle;
    };
    /**
     * Stroke color (hex string or color name) or stroke object with advanced options
     */
    stroke?: string | number | {
        color: string | number;
        width: number;
        join?: "miter" | "round" | "bevel";
    };
    /**
     * Stroke width in pixels (used when stroke is a simple color)
     * @default 0
     */
    strokeWidth?: number;
    /**
     * Text alignment ('left', 'center', 'right')
     * @default 'center'
     */
    align?: "left" | "center" | "right";
    /**
     * Shadow configuration
     */
    shadow?: {
        color?: string | number;
        alpha?: number;
        blur?: number;
        offsetX?: number;
        offsetY?: number;
    };
    /**
     * Word wrap width (0 = no wrap)
     * @default 0
     */
    wordWrapWidth?: number;
    /**
     * Word wrap mode ('break-word' or 'normal')
     * @default 'break-word'
     */
    wordWrapMode?: "break-word" | "normal";
    /**
     * Whether to enable word wrap
     * @default true
     */
    wordWrap?: boolean;
    /**
     * Vertical alignment ('top', 'center', 'bottom')
     * @default 'bottom'
     */
    verticalAlign?: "top" | "center" | "bottom";
    /**
     * Line height (multiplier)
     * @default 1
     */
    lineHeight?: number;
    /**
     * Letter spacing in pixels
     * @default 0
     */
    letterSpacing?: number;
    /**
     * Text case transformation
     * @default 'none'
     */
    textCase?: "none" | "uppercase" | "lowercase" | "title";
    /**
     * Media ID to which the captions were applied
     */
    mediaId?: string;
    /**
     * Internal flag to skip automatic positioning
     */
    initialLayoutApplied?: boolean;
    /**
     * Words per line mode ('single' or 'multiple')
     * @default 'multiple'
     */
    wordsPerLine?: "single" | "multiple";
    wordAnimation?: ICaptionWordAnimation;
    textBoxStyle?: ITextBoxStyle;
}
/**
 * Caption clip using Canvas 2D for rendering
 * Each instance represents a single caption segment
 *
 * @example
 * const captionClip = new CaptionClip('Hello World', {
 *   fontSize: 44,
 *   fontFamily: 'Arial',
 *   fill: '#ffffff',
 *   videoWidth: 1280,
 *   videoHeight: 720,
 * });
 * captionClip.display.from = 0;
 * captionClip.duration = 3e6; // 3 seconds
 */
export declare class Caption extends BaseClip<ICaptionEvents> implements IClip {
    readonly type = "Caption";
    ready: IClip["ready"];
    private _meta;
    get meta(): {
        duration: number;
        width: number;
        height: number;
    };
    animate(time: number): void;
    private _visualPaddingX;
    private _visualPaddingY;
    private _lastTickTime;
    get width(): number;
    set width(v: number);
    get height(): number;
    set height(v: number);
    get left(): number;
    set left(v: number);
    get top(): number;
    set top(v: number);
    private _initialLayoutApplied;
    private _isXPositionedManually;
    private _isWidthConstrained;
    private _lastContentWidth;
    private _lastContentHeight;
    private _lastProcessedText;
    private _text;
    /**
     * Caption text content (hybrid JSON structure)
     */
    get text(): string;
    set text(v: string);
    get style(): ICaptionStyle;
    set style(v: Partial<ICaptionOpts> | ICaptionStyle);
    get wordsPerLine(): "single" | "multiple";
    set wordsPerLine(v: "single" | "multiple");
    get fontFamily(): string;
    set fontFamily(v: string);
    get fontUrl(): string;
    set fontUrl(v: string);
    get fontSize(): number;
    set fontSize(v: number);
    get fontWeight(): string | number;
    set fontWeight(v: string | number);
    get fontStyle(): "normal" | "italic" | "oblique";
    set fontStyle(v: "normal" | "italic" | "oblique");
    get color(): ICaptionOpts["color"];
    set color(v: ICaptionOpts["color"]);
    get align(): "left" | "center" | "right";
    set align(v: "left" | "center" | "right");
    get stroke(): ICaptionOpts["stroke"];
    set stroke(v: ICaptionOpts["stroke"]);
    get strokeWidth(): number;
    set strokeWidth(v: number);
    get shadow(): ICaptionOpts["shadow"];
    set shadow(v: ICaptionOpts["shadow"]);
    get caption(): ICaptionOpts["caption"];
    set caption(v: ICaptionOpts["caption"]);
    get textBoxStyle(): ITextBoxStyle;
    set textBoxStyle(v: ITextBoxStyle);
    /**
     * Text case proxy
     */
    get textCase(): string;
    set textCase(v: "none" | "uppercase" | "lowercase" | "title");
    /**
     * Unique identifier for this clip instance
     */
    id: string;
    /**
     * Media ID of the source clip
     */
    get mediaId(): string | undefined;
    set mediaId(v: string | undefined);
    /**
     * Array of effects to be applied to this clip
     * Each effect specifies key, startTime, duration, and optional targets
     */
    effects: Array<{
        id: string;
        key: string;
        startTime: number;
        duration: number;
    }>;
    /**
     * Words getter for the clip
     */
    get words(): ICaptionWord[];
    /**
     * Words setter that triggers re-render and ensures consistency
     */
    set words(v: ICaptionWord[]);
    private opts;
    private pixiTextContainer;
    private renderTexture;
    private wordTexts;
    private textStyle;
    private textStyleBase;
    private _refreshing;
    private _needsRefresh;
    private externalRenderer;
    private pixiApp;
    private originalOpts;
    constructor(text: string, opts?: ICaptionOpts, renderer?: Application["renderer"]);
    /**
     * Update text styling options and refresh the caption rendering
     */
    updateStyle(opts: Partial<ICaptionOpts>): Promise<void>;
    private refreshCaptions;
    private lastLoggedTime;
    updateState(currentTime: number): void;
    /**
     * Get the PixiJS Texture (RenderTexture) for optimized rendering in Studio
     */
    getTexture(): Promise<Texture | null>;
    offscreenRender(ctx: CanvasRenderingContext2D, time: number): Promise<{
        audio: Float32Array[];
        done: boolean;
    }>;
    /**
     * Set an external renderer (e.g., from Studio) to avoid creating our own Pixi App
     */
    setRenderer(renderer: Application["renderer"]): void;
    private getRenderer;
    tick(time: number): Promise<{
        video: ImageBitmap;
        state: "success";
    }>;
    split(_time: number): Promise<[this, this]>;
    addEffect(effect: {
        id: string;
        key: string;
        startTime: number;
        duration: number;
    }): void;
    editEffect(effectId: string, newEffectData: Partial<{
        key: string;
        startTime: number;
        duration: number;
    }>): void;
    removeEffect(effectId: string): void;
    clone(): Promise<this>;
    destroy(): void;
    toJSON(main?: boolean): CaptionJSON;
    /**
     * Create a Caption instance from a JSON object (fabric.js pattern)
     * @param json The JSON object representing the clip
     * @returns Promise that resolves to a Caption instance
     */
    static fromObject(json: CaptionJSON): Promise<Caption>;
    getVisibleHandles(): Array<"tl" | "tr" | "bl" | "br" | "ml" | "mr" | "mt" | "mb" | "rot">;
    private drawRoundedTiktokPath;
}
