declare module "@jwplayer/jwplayer-react-native" {
  import React from "react";
  import { ViewStyle } from "react-native";

  // ============================================================================
  // UNIFIED CONFIGURATION TYPES
  // ============================================================================
  // For detailed type definitions, see types/ directory
  // Types are also available by importing from '@jwplayer/jwplayer-react-native/types'
  
  // Main configuration interface - see types/unified-config.d.ts for full documentation
  export interface JWPlayerConfig {
    license: string;
    file?: string;
    sources?: any[];
    playlist?: any[] | string;
    playlistIndex?: number;
    autostart?: boolean;
    mute?: boolean;
    repeat?: boolean;
    preload?: 'auto' | 'none' | boolean;
    stretching?: 'uniform' | 'fill' | 'exactfit' | 'none';
    playbackRates?: number[];
    playbackRateControls?: boolean;
    bitrateUpperBound?: number;
    advertising?: any;
    related?: any;
    pid?: string;
    playerId?: string;
    styling?: any;
    uiConfig?: any;
    backgroundAudioEnabled?: boolean;
    category?: string;
    categoryOptions?: string[];
    mode?: string;
    forceLegacyConfig?: boolean;
    playlistItemCallbackEnabled?: boolean;
    playerInModal?: boolean;
    fullScreenOnLandscape?: boolean;
    landscapeOnFullScreen?: boolean;
    portraitOnExitFullScreen?: boolean;
    exitFullScreenOnPortrait?: boolean;
    enableLockScreenControls?: boolean;
    pipEnabled?: boolean;
    useTextureView?: boolean;
    allowCrossProtocolRedirectsSupport?: boolean;
    displaytitle?: boolean;
    displayTitle?: boolean;
    displaydescription?: boolean;
    displayDescription?: boolean;
    nextupoffset?: string | number;
    thumbnailPreview?: number;
    logoView?: any;
    title?: string;
    description?: string;
    image?: string;
    tracks?: any[];
    starttime?: number;
    mediaid?: string;
    mediaId?: string;
    [key: string]: any;
  }
  
  // Main configuration type alias
  export type Config = JWPlayerConfig;
  
  // Re-export common types with proper names
  export type JWAdvertisingConfig = any;
  export type JWPlaylistItem = any;
  export type JWSource = any;
  export type JWTrack = any;
  export type JWImaDaiSettings = any;
  export type JWImaSdkSettings = any;
  export type JWAdBreak = any;
  export type JWAdRules = any;
  export type JWUiConfig = any;
  export type JWLogoView = any;
  export type JWRelatedConfig = any;
  export type JWStyling = any;
  export type ThumbnailPreview = 101 | 102 | 103;
  export type Stretching = 'uniform' | 'fill' | 'exactfit' | 'none';

  // ============================================================================
  // BACKWARD COMPATIBILITY
  // ============================================================================
  
  /**
   * @deprecated Use JWPlayerConfig or Config instead
   * Maintained for backward compatibility
   */
  interface JwConfig {
    pid?: string;
    mute?: boolean;
    forceLegacyConfig?: boolean;
    playlistItemCallbackEnabled?: boolean;
    useTextureView?: boolean;
    autostart?: boolean;
    nextupoffset?: string | number;
    repeat?: boolean;
    allowCrossProtocolRedirectsSupport?: boolean;
    displaytitle?: boolean;
    displaydescription?: boolean;
    stretching?: string;
    thumbnailPreview?: number;
    preload?: boolean;
    playlist?: any[] | string;
    sources?: any[];
    file?: string;
    playlistIndex?: number;
    related?: any;
    uiConfig?: any;
    logoView?: any;
    advertising?: any;
    playbackRates?: number[];
    playbackRateControls?: boolean;
    license: string;
    playerInModal?: boolean;
    fullScreenOnLandscape?: boolean;
    landscapeOnFullScreen?: boolean;
    portraitOnExitFullScreen?: boolean;
    exitFullScreenOnPortrait?: boolean;
    enableLockScreenControls?: boolean;
    pipEnabled?: boolean;
    [key: string]: any;
  }

  // ============================================================================
  // TYPE ALIASES FOR BACKWARD COMPATIBILITY
  // ============================================================================

  /**
   * @deprecated Use Stretching from unified types
   */
  type JwStretching = Stretching;

  /**
   * @deprecated Use ThumbnailPreview from unified types
   */
  type JwThumbnailPreview = ThumbnailPreview;

  // Re-export advertising types with legacy names for backward compatibility
  /**
   * @deprecated Advertising types are now imported from unified types
   * Use JWAdvertisingConfig instead
   */
  type VmapAdvertisingConfig = import('./types').VmapAdvertisingConfig;
  type VastAdvertisingConfig = import('./types').VastAdvertisingConfig;
  type ImaVmapAdvertisingConfig = import('./types').ImaAdvertisingConfig;
  type ImaAdvertisingConfig = import('./types').ImaAdvertisingConfig;
  type ImaDaiAdvertisingConfig = import('./types').ImaDaiAdvertisingConfig;

  /**
   * @deprecated Use JWAdRules from unified types
   */
  type JwStartOnSeek = "pre" | "none";
  
  /**
   * @deprecated Use JWAdBreak from unified types
   */
  type JwAdType = "LINEAR" | "NONLINEAR";
  
  /**
   * @deprecated Use OmidSupport from unified types
   */
  type JwOmidSupport = "auto" | "enabled" | "disabled";
  
  /**
   * @deprecated Use LogoPosition from unified types
   */
  type JwLogoPosition = "topLeft" | "topRight" | "bottomLeft" | "bottomRight";

  // Re-export playlist and media types for backward compatibility
  /**
   * @deprecated These types are now imported from unified types
   * Direct usage is discouraged - import from './types' instead
   */
  type JwRelatedOnComplete = "hide" | "show" | "none" | "autoplay";
  type JwOnRelatedClick = "play" | "link";

  // ============================================================================
  // LEGACY TYPE DEFINITIONS
  // ============================================================================
  // The following types are maintained for backward compatibility with existing code.
  // New code should use the unified types imported from './types' above.
  // These legacy definitions may be removed in a future major version.
  
  /**
   * @deprecated Use types from './types' instead
   */
  interface AudioTrack {
    autoSelect: boolean;
    defaultTrack: boolean;
    groupId: string;
    language: string;
    name: string;
  }

  export interface QualityLevel {
    playListPosition: number;
    bitRate: number;
    label: string;
    height: number;
    width: number;
    index: number;
  }

  interface CastingDevice {
    name?: string;
    identifier?: string;
  }
  interface Source {
    file: string;
    label: string;
    default?: boolean;
  }

  type TrackKind = "captions" | "chapters" | "thumbnails";

  interface Track {
    file: string;
    label: string;
    kind: TrackKind;
    default?: boolean;
  }
  interface JWAdSettings {
    allowsBackgroundPlayback?: boolean;
    // Add other ad settings properties as needed
  }
  interface IMASettings {
    locale?: string;
    ppid?: string;
    maxRedirects?: number;
    sessionID?: string;
    debugMode?: boolean;
  }
  interface AdSchedule {
    tag: string;
    offset: string;
  }
  // interface CompanionAdSlot {
  //   viewId: string; // Reference to a UIView in the application
  //   size?: { width: number; height: number };
  // }
  interface GoogleDAIStream {
    videoID?: string;
    cmsID?: string;
    assetKey?: string;
    apiKey?: string;
    adTagParameters?: { [key: string]: string };
  }
  interface AdRule {
    startOn: number;
    frequency: number;
    timeBetweenAds: number;
    startOnSeek: 'none' | 'pre'; // Mapped from JWAdShownOnSeek
  }
  // interface FriendlyObstruction {
  //   viewId: string;
  //   purpose: 'mediaControls' | 'closeAd' | 'notVisible' | 'other'; // Mapped from JWFriendlyObstructionPurpose
  //   reason?: string;
  // }
  type ClientTypes = "vast" | "ima" | "ima_dai";
  interface VASTAdvertising {
    adSchedule?: AdSchedule[];
    adVmap?: string;
    tag?: string; // Vast xml url
    openBrowserOnAdClick?: boolean;
    adClient: "vast";
    adRules?: AdRule;
    adSettings?: JWAdSettings;
  }
  interface IMAAdvertising {
    adSchedule?: AdSchedule[];
    adVmap?: string;
    tag?: string; // Vast xml url
    adClient: "ima";
    adRules?: AdRule;
    imaSettings?: IMASettings;
    // companionAdSlots?: CompanionAdSlot[];
    // friendlyObstructions?: FriendlyObstruction[];
  }
  interface IMA_DAIAdvertising {
    adClient: "ima_dai";
    imaSettings?: IMASettings;
    // friendlyObstructions?: FriendlyObstruction[];
    googleDAIStream?: GoogleDAIStream;
  }
  type Advertising = VASTAdvertising | IMAAdvertising | IMA_DAIAdvertising;
  interface PlaylistItem {
    file: string;
    sources?: Source[];
    image?: string;
    title?: string;
    description?: string;
    mediaId?: string;
    adSchedule?: AdSchedule[];
    adVmap?: string;
    tracks?: Track[];
    recommendations?: string;
    startTime?: number;
    autostart?: boolean;
    /**
     * Data to be passed to Chromecast receiver (optional and typically used for DRM implementations)
     * 
     * Only made available in legacy objects as there is no way to pass this otherwise
     */
    userInfo?: { [key: string]: any };
  }
  type RelatedOnClicks = "play" | "link";
  type RelatedOnCompletes = "show" | "hide" | "autoplay";
  interface Related {
    onClick?: RelatedOnClicks;
    onComplete?: RelatedOnCompletes;
    heading?: string;
    url?: string;
    autoplayMessage?: string;
    autoplayTimer?: number;
  }
  interface Font {
    name?: string;
    size?: number;
  }
  type EdgeStyles = "none" | "dropshadow" | "raised" | "depressed" | "uniform";

  // All `Styling` is only intended to be used with iOS. Android requires overloading
  // of the JWP IDs seen here: https://docs.jwplayer.com/players/docs/android-styling-guide
  interface Styling {
    colors?: {
      buttons?: string;
      backgroundColor?: string;
      fontColor?: string;
      timeslider?: { 
        thumb?: string;
        rail?: string;
        slider?: string;
      };
    };
    font?: Font;
    showTitle?: boolean;
    showDesc?: boolean;
    captionsStyle?: {
      font?: Font;
      fontColor?: string;
      backgroundColor?: string;
      highlightColor?: string;
      edgeStyle?: EdgeStyles;
    };
    menuStyle?: {
      font?: Font;
      fontColor?: string;
      backgroundColor?: string;
    };
  }
  type Preloads = "auto" | "none";
  type InterfaceBehaviors = "normal" | "hidden" | "onscreen";
  type UIGroups =
    | "overlay"
    | "control_bar"
    | "center_controls"
    | "next_up"
    | "error"
    | "playlist"
    | "controls_container"
    | "settings_menu"
    | "quality_submenu"
    | "captions_submenu"
    | "playback_submenu"
    | "audiotracks_submenu"
    | "casting_menu";
  type AudioSessionCategory =
    | "Ambient"
    | "SoloAmbient"
    | "Playback"
    | "Record"
    | "PlayAndRecord"
    | "MultiRoute";
  type AudioSessionCategoryOptions =
    | "MixWithOthers"
    | "DuckOthers"
    | "AllowBluetooth"
    | "DefaultToSpeaker"
    | "InterruptSpokenAudioAndMix"
    | "AllowBluetoothA2DP"
    | "AllowAirPlay"
    | "OverrideMutedMicrophone";
  type AudioSessionMode =
    | "Default"
    | "VoiceChat"
    | "VideoChat"
    | "GameChat"
    | "VideoRecording"
    | "Measurement"
    | "MoviePlayback"
    | "SpokenAudio"
    | "VoicePrompt";
  type JWControlType =
    | "forward"
    | "rewind"
    | "pip"
    | "airplay"
    | "chromecast"
    | "next"
    | "previous"
    | "settings"
    | "languages"
    | "fullscreen";
  /**
   * @deprecated Legacy iOS config interface - use JWPlayerConfig instead
   */
  interface LegacyIOSConfig {
    license: string;
    advertising?: Advertising;
    autostart?: boolean;
    controls?: boolean;
    repeat?: boolean;
    nextUpStyle?: { offsetSeconds: number; offsetPercentage: number };
    styling?: Styling;
    backgroundAudioEnabled?: boolean;
    category?: AudioSessionCategory;
    categoryOptions?: Array<AudioSessionCategoryOptions>;
    mode?: AudioSessionMode;
    fullScreenOnLandscape?: boolean;
    landscapeOnFullScreen?: boolean;
    portraitOnExitFullScreen?: boolean;
    exitFullScreenOnPortrait?: boolean;
    playerInModal?: boolean;
    playlist?: PlaylistItem[];
    stretching?: string;
    related?: Related;
    preload?: Preloads;
    interfaceBehavior?: InterfaceBehaviors;
    interfaceFadeDelay?: number;
    hideUIGroups?: UIGroups[];
    processSpcUrl?: string;
    fairplayCertUrl?: string;
    contentUUID?: string;
    viewOnly?: boolean;
    enableLockScreenControls?: boolean;
    pipEnabled?: boolean;
    offlineMessage?: string;
    offlineImage?: string;
    forceFullScreenOnLandscape?: boolean;
    forceLandscapeOnFullScreen?: boolean;
  }
  interface BaseEvent<T> {
    nativeEvent: T;
  }
  interface SeekEventProps {
    position: number;
    offset: number;
  }
  interface SeekedEventProps {
    position: number;
  }
  interface RateChangedEventProps {
    rate: number;
    at: number;
  }
  interface PlayerSetupErrorProps {
    errorMessage?: string;
    errorCode?: number;
  }
  interface PlayerErrorProps {
    error?: string;
    errorCode?: number;
    description?: string;
  }
  interface TimeEventProps {
    position: number;
    duration: number;
  }
  interface ControlBarVisibleEventProps {
    visible: boolean;
  }
  interface PlaylistEventProps {
    playlist: PlaylistItem[]
  }
  interface LoadEventProps {
    loadTime: number;
  }
  interface PlaylistItemEventProps {
    playlistItem: PlaylistItem;
    index?: number;
  }
  interface PlayerErrorEventProps {
    code: string;
    error: string;
  }
  interface PlayerWarningEventProps {
    code?: number;
    warning?: string;
    adErrorCode?: number; // Android only
  }
  interface AdEventProps {
    client: number;
    reason?: string;
    type: number;
  }
  // Overloaded type to be used in multiple error events
  interface CaptionsChangedEventProps {
    index?: number;
  }
  interface CaptionTrack {
    /** @platform android */
    file?: string;
    label: string;
    default: boolean;
  }
  interface CaptionsListEventProps {
    index: number;
    tracks?: CaptionTrack[];
    /** @deprecated Use tracks array instead */
    file?: string;
    /** @deprecated Use tracks array instead */
    label?: string;
    /** @deprecated Use tracks array instead */
    default?: boolean;
  }
  interface CastingEventProps {
    device?: string;
    active?: boolean;
    available?: boolean;
  }
  interface CastingDeviceEventProps {
    device?: string;
  }
  interface CastingErrorEventProps {
    error?: string;
  }
  interface CastingDevice {
    name: string;
    identifier: string;
  }
  interface CastingDevicesAvailableEventProps {
    /**
     * JSON-encoded `CastingDevice[]`. Parse with `JSON.parse()` before use.
     * @platform ios
     */
    devices?: string;
  }
  interface VisibleEventProps {
    visible: boolean;
  }
  interface ScreenTappedEventProps {
    x: number;
    y: number;
  }
  interface UpdateBufferEventProps {
    percent: number;
    position: number;
  }
  interface PlayerSize {
    width: number;
    height: number;
  }
  interface PlayerSizeChangeEventProps {
    /**
     * JSON-encoded `{ oldSize: PlayerSize; newSize: PlayerSize }`.
     * Parse with `JSON.parse()` before use.
     * @platform ios
     */
    sizes?: string;
  }
  type NativeError = (event: BaseEvent<PlayerErrorEventProps> | BaseEvent<PlayerSetupErrorProps> | BaseEvent<PlayerErrorProps>) => void;
  type NativeWarning = (event: BaseEvent<PlayerWarningEventProps>) => void;
  interface PropsType {
    config: JWPlayerConfig | JwConfig | LegacyIOSConfig;
    style?: ViewStyle;
    controls?: boolean;
    forceLegacyConfig?: boolean;
    onPlayerReady?: () => void;
    onPlaylist?: (event: BaseEvent<PlaylistEventProps>) => void;
    onLoaded? : (event: BaseEvent<LoadEventProps>) => void;
    onBeforePlay?: () => void;
    onBeforeComplete?: () => void;
    onComplete?: () => void;
    onPlay?: () => void;
    onPause?: () => void;
    onSeek?: (event: BaseEvent<SeekEventProps>) => void;
    onSeeked?: (event?: BaseEvent<SeekedEventProps>) => void;
    onRateChanged?: (event?: BaseEvent<RateChangedEventProps>) => void;
    onSetupPlayerError?: NativeError;
    onPlayerError?: NativeError;
    onPlayerWarning?: NativeWarning; 
    onPlayerAdError?: NativeError; 
    onPlayerAdWarning?: NativeWarning; 
    onAdEvent?: (event: BaseEvent<AdEventProps>) => void;
    onAdTime?: (event: BaseEvent<TimeEventProps>) => void;
    onBuffer?: () => void;
    onTime?: (event: BaseEvent<TimeEventProps>) => void;
    onFullScreenRequested?: () => void;
    onFullScreen?: () => void;
    onFullScreenExitRequested?: () => void;
    onFullScreenExit?: () => void;
    onControlBarVisible?: (event: BaseEvent<ControlBarVisibleEventProps>) => void;
    onPlaylistComplete?: () => void;
    onPlaylistItem?: (event: BaseEvent<PlaylistItemEventProps>) => void;
    onPlaylistItemMetadataChanged?: (event: BaseEvent<PlaylistItemEventProps>) => void;
    onCaptionsChanged?: (event: BaseEvent<CaptionsChangedEventProps>) => void;
    onCaptionsList?: (event: BaseEvent<CaptionsListEventProps>) => void;
    onAudioTracks?: () => void;
    /** @platform ios */
    onIdle?: () => void;
    /** @platform ios */
    onVisible?: (event: BaseEvent<VisibleEventProps>) => void;
    /** @platform ios */
    onAttemptPlay?: () => void;
    /** @platform ios */
    onUpdateBuffer?: (event: BaseEvent<UpdateBufferEventProps>) => void;
    /** @platform ios */
    onScreenTapped?: (event: BaseEvent<ScreenTappedEventProps>) => void;
    /** @platform ios */
    onPlayerSizeChange?: (event: BaseEvent<PlayerSizeChangeEventProps>) => void;
    onCasting?: (event: BaseEvent<CastingEventProps>) => void;
    /** @platform ios */
    onCastingDevicesAvailable?: (event: BaseEvent<CastingDevicesAvailableEventProps>) => void;
    /** @platform ios */
    onConnectedToCastingDevice?: (event: BaseEvent<CastingDeviceEventProps>) => void;
    /** @platform ios */
    onDisconnectedFromCastingDevice?: (event: BaseEvent<CastingErrorEventProps>) => void;
    /** @platform ios */
    onConnectionTemporarilySuspended?: () => void;
    /** @platform ios */
    onConnectionRecovered?: () => void;
    /** @platform ios */
    onConnectionFailed?: (event: BaseEvent<CastingErrorEventProps>) => void;
    /** @platform ios */
    onCastingEnded?: (event: BaseEvent<CastingErrorEventProps>) => void;
    /** @platform ios */
    onCastingFailed?: (event: BaseEvent<CastingErrorEventProps>) => void;
    shouldComponentUpdate?: (nextProps: any, nextState: any) => boolean;
    onBeforeNextPlaylistItem?: (event: BaseEvent<PlaylistItemEventProps>) => void;
  }

  export const JWPlayerAdEvents: {
    /// This event is reported when the ad break has come to an end.
    JWAdEventTypeAdBreakEnd: 0;
    /// This event is reported when the ad break has begun.
    JWAdEventTypeAdBreakStart: 1;
    /// This event is reported when the user taps the ad.
    JWAdEventTypeClicked: 2;
    /// This event is reported when the ad is done playing.
    JWAdEventTypeComplete: 3;
    /// This event is used to report the ad impression, supplying additional detailed information about the ad.
    JWAdEventTypeImpression: 4;
    /// This event reports meta data information associated with the ad.
    JWAdEventTypeMeta: 5;
    /// The event is reported when the ad pauses.
    JWAdEventTypePause: 6;
    /// This event is reported when the ad begins playing, even in the middle of the stream after it was paused.
    JWAdEventTypePlay: 7;
    /// The event reports data about the ad request, when the ad is about to be loaded.
    JWAdEventTypeRequest: 8;
    /// This event reports the schedule of ads across the currently playing content.
    JWAdEventTypeSchedule: 9;
    /// This event is reported when the user skips the ad.
    JWAdEventTypeSkipped: 10;
    /// This event is reported when the ad begins.
    JWAdEventTypeStarted: 11;
    /// This event relays information about ad companions.
    JWAdEventTypeCompanion: 12;
    /// This event is reported when the ad has loaded. (Android only)
    JWAdEventTypeLoaded: 13;
    /// This event is reported when the ad VAST XML has loaded. (Android only)
    JWAdEventTypeLoadedXml: 14;
    /// This event is reported when an ad break was ignored (e.g. because another is playing). (Android only)
    JWAdEventTypeAdBreakIgnored: 15;
  };

  export const JWPlayerState: {
    JWPlayerStateUnknown?: number;
    JWPlayerStateIdle: number;
    JWPlayerStateBuffering: number;
    JWPlayerStatePlaying: number;
    JWPlayerStatePaused: number;
    JWPlayerStateComplete: number;
    JWPlayerStateError: number | null;
  };

  export const JWPlayerAdClients: {
    JWAdClientJWPlayer: 0;
    JWAdClientGoogleIMA: 1;
    JWAdClientGoogleIMADAI: 2;
    JWAdClientUnknown: 3;
  };

  export default class JWPlayer extends React.Component<PropsType> {
    quite(): void;
    pause(): void;
    play(): void;
    stop(): void;
    toggleSpeed(): void;
    setSpeed(speed: number): void;
    setCurrentQuality(index: number): void;
    currentQuality(): number;
    getQualityLevels(): Promise<QualityLevel[] | null>;
    setVolume(volume: number): void;
    setPlaylistIndex(index: number): void;
    setControls(show: boolean): void;
    setLockScreenControls(show: boolean): void;
    seekTo(time: number): void;
    changePlaylist(fileUrl: string): void;
    /**
     * Side load playlist items into an already setup player
     * @param playlistItems `PlaylistItem` or `JWPlaylistItem`
     */
    loadPlaylist(playlistItems: PlaylistItem[] | JWPlaylistItem[]): void;
    /**
     * Side load playlist via URL into an already setup player
     * @param playlistUrl URL for playlist to load (format for response: json)
     */
    loadPlaylistWithUrl(playlistUrl: string): void;
    /**
     * Updates the currently playing playlist item's metadata without reloading.
     * Only non-null fields are applied; omitted fields leave existing values unchanged.
     * Fires `onPlaylistItemMetadataChanged` with the updated item on both platforms.
     *
     * @param metadata.refreshNotification **Android-only, temporary workaround.**
     *   When `true` on Android with `backgroundAudioEnabled: true`, the RN bridge cycles the
     *   foreground MediaService after updating metadata so the lock-screen / notification shade
     *   rebuilds with the new title and description. Without this flag the JW Android SDK
     *   updates the MediaSession metadata but leaves the visible notification stale. Expect a
     *   brief notification flicker and a momentary audio-focus transition while the service
     *   rebinds.
     *
     *   Known limitation: the poster image is downloaded asynchronously by the SDK, so the
     *   rebuilt notification typically still shows the previous poster. The poster refreshes
     *   on the next playback state change (pause/play, seek).
     *
     *   Remove this flag from your call site once a future JW Android SDK release refreshes the
     *   notification natively. No-op on iOS — JWPlayerKit already refreshes the lock-screen
     *   controls via LockScreenControlsHandler.
     */
    setPlaylistItemMetadata(metadata: {
        title?: string | null;
        description?: string | null;
        image?: string | null;
        refreshNotification?: boolean;
    }): void;
    setFullscreen(fullScreen: boolean): void;
    time(): Promise<number | null>;
    position(): Promise<number | null>;
    togglePIP(): void;
    setUpCastController(): void;
    presentCastDialog(): void;
    connectedDevice(): Promise<CastingDevice | null>;
    availableDevices(): Promise<CastingDevice[] | null>;
    castState(): Promise<number | null>;
    playerState(): Promise<number | null>;
    getAudioTracks(): Promise<AudioTrack[] | null>;
    getCurrentAudioTrack(): Promise<number | null>;
    setCurrentAudioTrack(index: number): void;
    setCurrentCaptions(index: number): void;
    getCurrentCaptions(): Promise<number | null>; 
    setVisibility(visibility: boolean, controls: JWControlType[]): void;
    /**
     * Reconfigures or recreates the player with a new configuration.
     * 
     * IMPORTANT: This method should only be called after the player has been properly
     * initialized and is ready (i.e., after onPlayerReady has fired). Calling this
     * method before the player is ready may lead to undefined behavior.
     * 
     * **Platform Behavior:**
     * 
     * - **iOS**: Always performs a complete player recreation by:
     *   1. Safely handling PiP state if active (waits for PiP to close)
     *   2. Performing complete cleanup of the current player instance
     *   3. Creating a new player instance with the provided config
     * 
     * - **Android**: Intelligently determines whether to recreate or reconfigure:
     *   - ~90% of cases: Reconfigures existing player (preserves player instance, faster)
     *   - ~10% of cases: Recreates player (only when necessary, e.g., license changes)
     *   - Automatically handles state preservation (fullscreen, PiP)
     * 
     * **Use this method when you need to:**
     * - Switch to a new playlist or video programmatically
     * - Update player configuration dynamically (e.g., from user settings)
     * - Handle content changes during PiP mode
     * - Write cross-platform code (same API works on both platforms)
     * 
     * **Do NOT use this method:**
     * - Before the player is ready (wait for onPlayerReady)
     * - When the player is not properly initialized
     * 
     * **For simple playlist updates, consider using `loadPlaylist()` instead.**
     * 
     * @example
     * ```typescript
     * // Cross-platform example - works the same on both iOS and Android
     * const switchVideo = () => {
     *   playerRef.current?.recreatePlayerWithConfig({
     *     license: 'YOUR_LICENSE_KEY',
     *     playlist: [{
     *       file: 'https://example.com/video.mp4',
     *       title: 'New Video'
     *     }],
     *     autostart: true
     *   });
     * };
     * 
     * // Use inside onPlayerReady
     * <JWPlayer
     *   ref={playerRef}
     *   config={initialConfig}
     *   onPlayerReady={() => {
     *     // Now safe to use recreatePlayerWithConfig
     *     console.log('Player ready, can switch content if needed');
     *   }}
     * />
     * ```
     * 
     * @param config The new configuration to apply
     * @throws May throw if called before player is ready or with invalid config
     */
    recreatePlayerWithConfig(config: JWPlayerConfig | JwConfig | LegacyIOSConfig): void;
    /**
     * Only called inside `onBeforeNextPlaylistItem` callback, and once per callback
     * @param playlistItem  `PlaylistItem` or  `JWPlaylistItem`
     */
    resolveNextPlaylistItem(playlistItem: PlaylistItem | JWPlaylistItem): void;
  }
}
