import { FrameController, FrameRenderable, FrameState } from "../preview/FrameController.js";
import { QualityUpgradeScheduler } from "../preview/QualityUpgradeScheduler.js";
import { TemporalMixinInterface } from "./EFTemporal.js";
import { EFMedia } from "./EFMedia.js";
import { ContainerInfo } from "./ContainerInfo.js";
import { ElementPositionInfo } from "./ElementPositionInfo.js";
import { RenderToVideoOptions } from "../preview/renderTimegroupToVideo.types.js";
import "./EFPanZoom.js";
import "../canvas/EFCanvas.js";
import "../gui/hierarchy/EFHierarchy.js";
import "../gui/EFFilmstrip.js";
import "../gui/EFFitScale.js";
import "../gui/EFWorkbench.js";
import * as lit0 from "lit";
import { LitElement, PropertyValues } from "lit";
import * as lit_html0 from "lit-html";

//#region src/elements/EFTimegroup.d.ts
type FrameTaskCallback = (info: {
  ownCurrentTimeMs: number;
  currentTimeMs: number;
  durationMs: number;
  percentComplete: number;
  element: EFTimegroup;
}) => void | Promise<void>;
/**
 * Result of createRenderClone() - contains the clone, its container, and cleanup function.
 */
interface RenderCloneResult {
  /** The cloned timegroup, fully functional with its own time state */
  clone: EFTimegroup;
  /** The offscreen container holding the clone */
  container: HTMLElement;
  /** Call this to remove the clone from DOM and clean up */
  cleanup: () => void;
}
/**
 * Initializer function type for setting up JavaScript behavior on timegroup instances.
 * This function is called on both the prime timeline and each render clone.
 *
 * CONSTRAINTS:
 * - MUST be synchronous (no async/await, no Promise return)
 * - MUST complete in <2000ms (error) or <100ms (warning)
 * - Should only register callbacks and set up behavior, not do expensive work
 * - GPU operations (WebGL context creation, shader compilation) may take up to ~1s
 */
type TimegroupInitializer = (timegroup: EFTimegroup) => void;
/**
 * The four timegroup modes define how duration is calculated:
 * - "fit": Inherits duration from parent timegroup
 * - "fixed": Uses explicit duration attribute
 * - "sequence": Sum of child durations minus overlaps
 * - "contain": Maximum of child durations
 */
type TimeMode = "fit" | "fixed" | "sequence" | "contain";
/**
 * Per-phase timing data returned by seekForRender().
 * All values are in milliseconds.
 */
interface SeekForRenderTiming {
  updateComplete1Ms: number;
  updateComplete2Ms: number;
  updateComplete3Ms: number;
  textSegmentsMs: number;
  renderFrameMs: number;
  renderFrameQueryMs: number;
  renderFramePrepareMs: number;
  renderFrameDrawMs: number;
  renderFrameAnimsMs: number;
  frameTasksMs: number;
  totalMs: number;
}
declare const EFTimegroup_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
declare class EFTimegroup extends EFTimegroup_base implements FrameRenderable {
  #private;
  static get observedAttributes(): string[];
  static styles: lit0.CSSResult;
  /** @internal */
  _timeGroupContext: this;
  /** @internal */
  efContext: this;
  shouldAutoReady(): boolean;
  get mode(): TimeMode;
  set mode(value: TimeMode);
  get overlapMs(): number;
  set overlapMs(value: number);
  /**
   * Initializer function for setting up JavaScript behavior on this timegroup.
   * This function is called ONCE per instance - on the prime timeline when first connected,
   * and on each render clone when created.
   *
   * Use this to register frame callbacks, set up event listeners, or initialize state.
   * The same initializer code runs on both prime and clones, eliminating duplication.
   *
   * CONSTRAINTS:
   * - MUST be synchronous (no async/await, no Promise return)
   * - MUST complete in <100ms (error thrown) or <10ms (warning logged)
   * - Should only register callbacks and set up behavior, not do expensive work
   *
   * TIMING:
   * - If set before element connects to DOM: runs automatically after connectedCallback
   * - If set after element is connected: runs immediately
   * - Clones automatically copy and run the initializer when created
   *
   * @example
   * ```javascript
   * const tg = document.querySelector('ef-timegroup');
   * tg.initializer = (instance) => {
   *   // Runs once on prime timeline, once on each clone
   *   instance.addFrameTask((info) => {
   *     // Update content based on time
   *   });
   * };
   * ```
   * @public
   */
  get initializer(): TimegroupInitializer | undefined;
  set initializer(fn: TimegroupInitializer | undefined);
  /** @public */
  fps: number;
  /**
   * When true, automatically seeks to frame 0 after media durations are loaded.
   * Only applies to root timegroups (timegroups that are not nested inside another timegroup).
   * This ensures the first frame is rendered immediately on initialization.
   */
  autoInit: boolean;
  /**
   * When true, automatically wraps this root timegroup with an ef-workbench element.
   * The workbench provides development UI including hierarchy panel, timeline, and playback controls.
   * Only applies to root timegroups.
   * @public
   */
  workbench: boolean;
  attributeChangedCallback(name: string, old: string | null, value: string | null): void;
  /** @public */
  fit: "none" | "contain" | "cover";
  /** @internal */
  isRestoringFromLocalStorage(): boolean;
  /** @internal - Used by PlaybackController to set restoration state */
  setRestoringFromLocalStorage(value: boolean): void;
  /**
   * Get the frame controller for centralized rendering coordination.
   * @public
   */
  get frameController(): FrameController;
  /**
   * Get the quality upgrade scheduler for background segment fetching.
   * @public
   */
  get qualityUpgradeScheduler(): QualityUpgradeScheduler;
  /**
   * Query timegroup's readiness state for a given time.
   * Timegroups are always ready (no async preparation needed).
   * @public
   */
  getFrameState(_timeMs: number): FrameState;
  /**
   * Async preparation phase (no-op for timegroups).
   * Timegroups don't need preparation - they just coordinate child rendering.
   * @public
   */
  prepareFrame(_timeMs: number, _signal: AbortSignal): Promise<void>;
  /**
   * Synchronous render phase - executes custom frame callbacks.
   * Called by FrameController after all preparation is complete.
   * Kicks off async frame callbacks without blocking (they run in background).
   * @public
   */
  renderFrame(_timeMs: number): void;
  /**
   * Get the effective FPS for this timegroup.
   * During rendering, uses the render options FPS if available.
   * Otherwise uses the configured fps property.
   * @public
   */
  get effectiveFps(): number;
  /**
   * Get the current content epoch (used by thumbnail cache).
   * The epoch increments whenever visual content changes.
   * @public
   */
  get contentEpoch(): number;
  /**
   * Increment content epoch (called when visual content changes).
   * This invalidates cached thumbnails by changing their cache keys.
   * @public
   */
  incrementContentEpoch(): void;
  /**
   * Request a frame re-render at the current time.
   *
   * Use this when the source-to-timeline mapping has changed (e.g., sourcein/sourceout)
   * but currentTimeMs hasn't. The FrameController only re-renders when currentTimeMs
   * or durationMs change, so this provides a way for child elements to request a
   * re-render when their internal state changes the visual output.
   * @public
   */
  requestFrameRender(): void;
  /** @public */
  set currentTime(time: number);
  /** @public */
  get currentTime(): number;
  /** @public */
  set currentTimeMs(ms: number);
  /** @public */
  get currentTimeMs(): number;
  /**
   * The time the user last requested via seek/scrub.
   * Preview systems should use this instead of currentTimeMs to avoid
   * seeing intermediate times during batch operations (thumbnails, export).
   * @public
   */
  get userTimeMs(): number;
  /**
   * Seek to a specific time and wait for all frames to be ready.
   * This is the recommended way to seek in tests and programmatic control.
   *
   * Combines seeking (Purpose 3) with frame rendering (Purpose 4) to ensure
   * all visible elements are ready after the seek completes.
   *
   * Updates both the source time AND userTimeMs (what the preview displays).
   *
   * @param timeMs - Time in milliseconds to seek to
   * @returns Promise that resolves when the seek is complete and all visible children are ready
   * @public
   */
  seek(timeMs: number): Promise<void>;
  /**
   * Optimized seek for render loops.
   * Unlike `seek()`, this:
   * - Skips waitForMediaDurations (already loaded at render setup)
   * - Skips localStorage persistence
   * - Uses FrameController for centralized element coordination
   *
   * Still waits for all content to be ready (Lit updates, element preparation, rendering).
   *
   * @param timeMs - Time in milliseconds to seek to
   * @internal
   */
  seekForRender(timeMs: number): Promise<SeekForRenderTiming>;
  /**
   * Determines if this is a root timegroup (no parent timegroups)
   * @public
   */
  get isRootTimegroup(): boolean;
  /**
   * Property-based frame task callback for React integration.
   * When set, automatically registers the callback as a frame task.
   * Setting a new value automatically cleans up the previous callback.
   * Set to null or undefined to remove the callback.
   *
   * @example
   * // React usage:
   * <Timegroup onFrame={({ ownCurrentTimeMs, percentComplete }) => {
   *   // Per-frame updates
   * }} />
   *
   * @public
   */
  get onFrame(): FrameTaskCallback | null;
  set onFrame(callback: FrameTaskCallback | null | undefined);
  /**
   * Register a custom frame task callback that will be executed during frame rendering.
   * The callback receives timing information and can be async or sync.
   * Multiple callbacks can be registered and will execute in parallel.
   *
   * @param callback - Function to execute on each frame
   * @returns A cleanup function that removes the callback when called
   * @public
   */
  addFrameTask(callback: FrameTaskCallback): () => void;
  /**
   * Remove a previously registered custom frame task callback.
   *
   * @param callback - The callback function to remove
   * @public
   */
  removeFrameTask(callback: FrameTaskCallback): void;
  /** @internal */
  saveTimeToLocalStorage(time: number): void;
  render(): lit_html0.TemplateResult<1>;
  /** @internal */
  loadTimeFromLocalStorage(): number | undefined;
  connectedCallback(): void;
  /**
   * Called when this timegroup becomes a root (no parent timegroup).
   * Sets up the playback listener after PlaybackController is created.
   * @internal
   */
  didBecomeRoot(): void;
  protected updated(changedProperties: PropertyValues): void;
  disconnectedCallback(): void;
  /**
   * Render the timegroup to an MP4 video file and trigger download.
   * Captures each frame at the specified fps, encodes using WebCodecs via
   * MediaBunny, and downloads the resulting video.
   *
   * Uses dynamic import to only load render utilities in browser context.
   *
   * @param options - Rendering options (fps, codec, bitrate, filename, etc.)
   * @returns Promise that resolves when video is downloaded
   * @public
   */
  renderToVideo(options?: RenderToVideoOptions): Promise<Uint8Array | undefined>;
  /**
   * Create an independent clone of this timegroup for rendering.
   * The clone is a fully functional ef-timegroup with its own animations
   * and time state, isolated from the original (Prime-timeline).
   *
   * OPTIONAL: An initializer can be set via `timegroup.initializer = (tg) => { ... }`
   * to re-run JavaScript setup (frame callbacks, React components) on each clone.
   *
   * This enables:
   * - Rendering without affecting user's preview position
   * - Concurrent renders with different clones
   * - Re-running JavaScript setup on each clone (if initializer is provided)
   *
   * @returns Promise resolving to clone, container, and cleanup function
   * @throws Error if initializer is async or takes too long
   * @public
   */
  createRenderClone(): Promise<RenderCloneResult>;
  /** @internal */
  get storageKey(): string;
  /** @internal */
  get intrinsicDurationMs(): number | undefined;
  /** @internal */
  get hasOwnDuration(): boolean;
  /** @public */
  get durationMs(): number;
  /** @internal */
  waitForMediaDurations(signal?: AbortSignal): Promise<void>;
  /** @internal */
  get childTemporals(): TemporalMixinInterface[];
  /**
   * Returns true if the timegroup should be wrapped with a workbench.
   *
   * A timegroup should be wrapped with a workbench if:
   * - It's being rendered (EF_RENDERING), OR
   * - The workbench property is set to true
   *
   * If the timegroup is already wrapped in a context provider like ef-preview,
   * it should NOT be wrapped in a workbench.
   * @internal
   */
  shouldWrapWithWorkbench(): boolean;
  /** @internal */
  wrapWithWorkbench(): void;
  /**
   * Returns media elements for playback audio rendering
   * For standalone media, returns [this]; for timegroups, returns all descendants
   * Used by PlaybackController for audio-driven playback
   * @internal
   */
  getMediaElements(): EFMedia[];
  /**
   * Render audio buffer for playback
   * Called by PlaybackController during live playback
   * Delegates to shared renderTemporalAudio utility for consistent behavior
   * @internal
   */
  renderAudio(fromMs: number, toMs: number, signal?: AbortSignal): Promise<AudioBuffer>;
  seekTask: {
    run(): void | Promise<number | undefined>;
    taskComplete: Promise<number | undefined>;
  };
  /**
   * Get container information for this timegroup.
   * Timegroups are always containers and can contain children.
   * Display mode is determined from computed styles.
   *
   * @public
   */
  getContainerInfo(): ContainerInfo;
  /**
   * Get position information for this timegroup.
   * Returns computed bounds, transform, and rotation.
   *
   * @public
   */
  getPositionInfo(): ElementPositionInfo | null;
}
declare global {
  interface HTMLElementTagNameMap {
    "ef-timegroup": EFTimegroup & Element;
  }
}
//#endregion
export { EFTimegroup };
//# sourceMappingURL=EFTimegroup.d.ts.map