import { LoadTypes, SponsorBlockChaptersLoaded, SponsorBlockChapterStarted, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, TrackData, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, VoicePacket, VoiceServer, WebSocketClosedEvent } from "./Utils";
import { Collection } from "@discordjs/collection";
import { EventEmitter } from "events";
import { Node, NodeOptions } from "./Node";
import { Player, PlayerOptions, Track } from "./Player";
import { VoiceState, Plugin } from "..";
import { ClientUser, User } from "discord.js";
/**
 * The main hub for interacting with Lavalink and using Magmastream,
 */
export declare class Synthra extends EventEmitter {
    /** The map of players. */
    readonly players: Collection<string, Player>;
    /** The map of nodes. */
    readonly nodes: Collection<string, Node>;
    /** The options that were set. */
    readonly options: ManagerOptions;
    initiated: boolean;
    /**
     * Initiates the Manager class.
     * @param options
     * @param options.plugins - An array of plugins to load.
     * @param options.nodes - An array of node options to create nodes from.
     * @param options.autoPlay - Whether to automatically play the first track in the queue when the player is created.
     * @param options.autoPlaySearchPlatform - The search platform autoplay will use. Fallback to Youtube if not found.
     * @param options.usePriority - Whether to use the priority when selecting a node to play on.
     * @param options.clientName - The name of the client to send to Lavalink.
     * @param options.defaultSearchPlatform - The default search platform to use when searching for tracks.
     * @param options.useNode - The strategy to use when selecting a node to play on.
     * @param options.trackPartial - The partial track search results to use when searching for tracks. This partials will always be presented on each track.
     * @param options.eventBatchDuration - The duration to wait before processing the collected player state events.
     * @param options.eventBatchInterval - The interval to wait before processing the collected player state events.
     */
    constructor(options: ManagerOptions);
    /**
     * Initiates the Manager.
     * @param clientId - The Discord client ID (required).
     * @param clusterId - The cluster ID which runs the current process (required).
     * @returns The manager instance.
     */
    init(clientId: string, clusterId?: number): this;
    /**
     * Searches the enabled sources based off the URL or the `source` property.
     * @param query
     * @param requester
     * @returns The search result.
     */
    search<T extends User | ClientUser = User | ClientUser>(query: string | SearchQuery, requester?: T): Promise<SearchResult>;
    /**
     * Creates a player or returns one if it already exists.
     * @param options The options to create the player with.
     * @returns The created player.
     */
    create(options: PlayerOptions): Player;
    /**
     * Returns a player or undefined if it does not exist.
     * @param guildId The guild ID of the player to retrieve.
     * @returns The player if it exists, undefined otherwise.
     */
    get(guildId: string): Player | undefined;
    /**
     * Destroys a player.
     * @param guildId The guild ID of the player to destroy.
     * @returns A promise that resolves when the player has been destroyed.
     */
    destroy(guildId: string): Promise<void>;
    /**
     * Creates a new node or returns an existing one if it already exists.
     * @param options - The options to create the node with.
     * @returns The created node.
     */
    createNode(options: NodeOptions): Node;
    /**
     * Destroys a node if it exists. Emits a debug event if the node is found and destroyed.
     * @param identifier - The identifier of the node to destroy.
     * @returns {void}
     * @emits {debug} - Emits a debug message indicating the node is being destroyed.
     */
    destroyNode(identifier: string): Promise<void>;
    /**
     * Attaches an event listener to the manager.
     * @param event The event to listen for.
     * @param listener The function to call when the event is emitted.
     * @returns The manager instance for chaining.
     */
    on<T extends keyof ManagerEvents>(event: T, listener: (...args: ManagerEvents[T]) => void): this;
    /**
     * Updates the voice state of a player based on the provided data.
     * @param data - The data containing voice state information, which can be a VoicePacket, VoiceServer, or VoiceState.
     * @returns A promise that resolves when the voice state update is handled.
     * @emits {debug} - Emits a debug message indicating the voice state is being updated.
     */
    updateVoiceState(data: VoicePacket | VoiceServer | VoiceState): Promise<void>;
    /**
     * Decodes an array of base64 encoded tracks and returns an array of TrackData.
     * Emits a debug event with the tracks being decoded.
     * @param tracks - An array of base64 encoded track strings.
     * @returns A promise that resolves to an array of TrackData objects.
     * @throws Will throw an error if no nodes are available or if the API request fails.
     */
    decodeTracks(tracks: string[]): Promise<TrackData[]>;
    /**
     * Decodes a base64 encoded track and returns a TrackData.
     * @param track - The base64 encoded track string.
     * @returns A promise that resolves to a TrackData object.
     * @throws Will throw an error if no nodes are available or if the API request fails.
     */
    decodeTrack(track: string): Promise<TrackData>;
    /**
     * Saves player states to the JSON file.
     * @param {string} guildId - The guild ID of the player to save
     */
    savePlayerState(guildId: string): Promise<void>;
    /**
     * Loads player states from the JSON file.
     * @param nodeId The ID of the node to load player states from.
     * @returns A promise that resolves when the player states have been loaded.
     */
    loadPlayerStates(nodeId: string): Promise<void>;
    /**
     * Returns the node to use based on the configured `useNode` and `usePriority` options.
     * If `usePriority` is true, the node is chosen based on priority, otherwise it is chosen based on the `useNode` option.
     * If `useNode` is "leastLoad", the node with the lowest load is chosen, if it is "leastPlayers", the node with the fewest players is chosen.
     * If `usePriority` is false and `useNode` is not set, the node with the lowest load is chosen.
     * @returns {Node} The node to use.
     */
    get useableNode(): Node;
    /**
     * Handles the shutdown of the process by saving all active players' states and optionally cleaning up inactive players.
     * This function is called when the process is about to exit.
     * It iterates through all players and calls {@link savePlayerState} to save their states.
     * Optionally, it also calls {@link cleanupInactivePlayers} to remove any stale player state files.
     * After saving and cleaning up, it exits the process.
     */
    handleShutdown(): Promise<void>;
    /**
     * Checks if the given data is a voice update.
     * @param data The data to check.
     * @returns Whether the data is a voice update.
     */
    private isVoiceUpdate;
    /**
     * Determines if the provided update is a valid voice update.
     * A valid update must contain either a token or a session_id.
     *
     * @param update - The voice update data to validate, which can be a VoicePacket, VoiceServer, or VoiceState.
     * @returns {boolean} - True if the update is valid, otherwise false.
     */
    private isValidUpdate;
    /**
     * Handles a voice server update by updating the player's voice state and sending the voice state to the Lavalink node.
     * @param player The player for which the voice state is being updated.
     * @param update The voice server data received from Discord.
     * @returns A promise that resolves when the voice state update is handled.
     * @emits {debug} - Emits a debug message indicating the voice state is being updated.
     */
    private handleVoiceServerUpdate;
    /**
     * Handles a voice state update by updating the player's voice channel and session ID if provided, or by disconnecting and destroying the player if the channel ID is null.
     * @param player The player for which the voice state is being updated.
     * @param update The voice state data received from Discord.
     * @emits {playerMove} - Emits a player move event if the channel ID is provided and the player is currently connected to a different voice channel.
     * @emits {playerDisconnect} - Emits a player disconnect event if the channel ID is null.
     */
    private handleVoiceStateUpdate;
    /**
     * Gets each player's JSON file
     * @param {string} guildId - The guild ID
     * @returns {string} The path to the player's JSON file
     */
    private getPlayerFilePath;
    /**
     * Serializes a Player instance to avoid circular references.
     * @param player The Player instance to serialize
     * @returns The serialized Player instance
     */
    private serializePlayer;
    /**
     * Checks for players that are no longer active and deletes their saved state files.
     * This is done to prevent stale state files from accumulating on the file system.
     */
    private cleanupInactivePlayers;
    /**
     * Returns the nodes that has the least load.
     * The load is calculated by dividing the lavalink load by the number of cores.
     * The result is multiplied by 100 to get a percentage.
     * @returns {Collection<string, Node>}
     */
    private get leastLoadNode();
    /**
     * Returns the nodes that have the least amount of players.
     * Filters out disconnected nodes and sorts the remaining nodes
     * by the number of players in ascending order.
     * @returns {Collection<string, Node>} A collection of nodes sorted by player count.
     */
    private get leastPlayersNode();
    /**
     * Returns a node based on priority.
     * The nodes are sorted by priority in descending order, and then a random number
     * between 0 and 1 is generated. The node that has a cumulative weight greater than or equal to the
     * random number is returned.
     * If no node has a cumulative weight greater than or equal to the random number, the node with the
     * lowest load is returned.
     * @returns {Node} The node to use.
     */
    private get priorityNode();
}
export interface Payload {
    /** The OP code */
    op: number;
    d: {
        guild_id: string;
        channel_id: string | null;
        self_mute: boolean;
        self_deaf: boolean;
    };
}
export interface ManagerOptions {
    /** Whether players should automatically play the next song. */
    autoPlay?: boolean;
    /** The search platform autoplay should use. Fallback to YouTube if not found.
     * Use enum `SearchPlatform`. */
    autoPlaySearchPlatform?: SearchPlatform;
    /** The client ID to use. */
    clientId?: string;
    /** Value to use for the `Client-Name` header. */
    clientName?: string;
    /** The array of shard IDs connected to this manager instance. */
    clusterId?: number;
    /** The default search platform to use.
     * Use enum `SearchPlatform`. */
    defaultSearchPlatform?: SearchPlatform;
    /** The last.fm API key.
     * If you need to create one go here: https://www.last.fm/api/account/create.
     * If you already have one, get it from here: https://www.last.fm/api/accounts. */
    lastFmApiKey: string;
    /** The maximum number of previous tracks to store. */
    maxPreviousTracks?: number;
    /** The array of nodes to connect to. */
    nodes?: NodeOptions[];
    /** A array of plugins to use. */
    plugins?: Plugin[];
    /** Whether the YouTube video titles should be replaced if the Author does not exactly match. */
    replaceYouTubeCredentials?: boolean;
    /** An array of track properties to keep. `track` will always be present. */
    trackPartial?: TrackPartial[];
    /** Use the least amount of players or least load? */
    useNode?: UseNodeOptions.LeastLoad | UseNodeOptions.LeastPlayers;
    /** Use priority mode over least amount of player or load? */
    usePriority?: boolean;
    /**
     * Function to send data to the websocket.
     * @param id The ID of the node to send the data to.
     * @param payload The payload to send.
     */
    send(id: string, payload: Payload): void;
}
export declare enum TrackPartial {
    /** The base64 encoded string of the track */
    Track = "track",
    /** The title of the track */
    Title = "title",
    /** The track identifier */
    Identifier = "identifier",
    /** The author of the track */
    Author = "author",
    /** The length of the track in milliseconds */
    Duration = "duration",
    /** The ISRC of the track */
    Isrc = "isrc",
    /** Whether the track is seekable */
    IsSeekable = "isSeekable",
    /** Whether the track is a stream */
    IsStream = "isStream",
    /** The URI of the track */
    Uri = "uri",
    /** The artwork URL of the track */
    ArtworkUrl = "artworkUrl",
    /** The source name of the track */
    SourceName = "sourceName",
    /** The thumbnail of the track */
    ThumbNail = "thumbnail",
    /** The requester of the track */
    Requester = "requester",
    /** The plugin info of the track */
    PluginInfo = "pluginInfo",
    /** The custom data of the track */
    CustomData = "customData"
}
export declare enum UseNodeOptions {
    LeastLoad = "leastLoad",
    LeastPlayers = "leastPlayers"
}
export type UseNodeOption = keyof typeof UseNodeOptions;
export declare enum SearchPlatform {
    AppleMusic = "amsearch",
    Bandcamp = "bcsearch",
    Deezer = "dzsearch",
    Jiosaavn = "jssearch",
    SoundCloud = "scsearch",
    Spotify = "spsearch",
    Tidal = "tdsearch",
    VKMusic = "vksearch",
    YouTube = "ytsearch",
    YouTubeMusic = "ytmsearch"
}
export declare enum PlayerStateEventTypes {
    AutoPlayChange = "playerAutoplay",
    ConnectionChange = "playerConnection",
    RepeatChange = "playerRepeat",
    PauseChange = "playerPause",
    QueueChange = "queueChange",
    TrackChange = "trackChange",
    VolumeChange = "volumeChange",
    ChannelChange = "channelChange",
    PlayerCreate = "playerCreate",
    PlayerDestroy = "playerDestroy"
}
interface PlayerStateUpdateEvent {
    changeType: PlayerStateEventTypes;
    details?: AutoplayChangeEvent | ConnectionChangeEvent | RepeatChangeEvent | PauseChangeEvent | QueueChangeEvent | TrackChangeEvent | VolumeChangeEvent | ChannelChangeEvent;
}
interface AutoplayChangeEvent {
    previousAutoplay: boolean;
    currentAutoplay: boolean;
}
interface ConnectionChangeEvent {
    changeType: "connect" | "disconnect";
    previousConnection: boolean;
    currentConnection: boolean;
}
interface RepeatChangeEvent {
    changeType: "dynamic" | "track" | "queue" | null;
    previousRepeat: string | null;
    currentRepeat: string | null;
}
interface PauseChangeEvent {
    previousPause: boolean | null;
    currentPause: boolean | null;
}
interface QueueChangeEvent {
    changeType: "add" | "remove" | "clear" | "shuffle" | "roundRobin" | "userBlock" | "autoPlayAdd";
    tracks?: Track[];
}
interface TrackChangeEvent {
    changeType: "start" | "end" | "previous" | "timeUpdate" | "autoPlay";
    track: Track;
    previousTime?: number | null;
    currentTime?: number | null;
}
interface VolumeChangeEvent {
    previousVolume: number | null;
    currentVolume: number | null;
}
interface ChannelChangeEvent {
    changeType: "text" | "voice";
    previousChannel: string | null;
    currentChannel: string | null;
}
export interface SearchQuery {
    /** The source to search from. */
    source?: SearchPlatform;
    /** The query to search for. */
    query: string;
}
export interface LavalinkResponse {
    loadType: LoadTypes;
    data: TrackData[] | PlaylistRawData;
}
export interface SearchResult {
    /** The load type of the result. */
    loadType: LoadTypes;
    /** The array of tracks from the result. */
    tracks: Track[];
    /** The playlist info if the load type is 'playlist'. */
    playlist?: PlaylistData;
}
export interface PlaylistRawData {
    info: {
        /** The playlist name. */
        name: string;
    };
    /** Addition info provided by plugins. */
    pluginInfo: object;
    /** The tracks of the playlist */
    tracks: TrackData[];
}
export interface PlaylistInfoData {
    /** Url to playlist. */
    url: string;
    /** Type is always playlist in that case. */
    type: string;
    /** ArtworkUrl of playlist */
    artworkUrl: string;
    /** Number of total tracks in playlist */
    totalTracks: number;
    /** Author of playlist */
    author: string;
}
export interface PlaylistData {
    /** The playlist name. */
    name: string;
    /** Requester of playlist. */
    requester: User | ClientUser;
    /** More playlist information. */
    playlistInfo: PlaylistInfoData[];
    /** The length of the playlist. */
    duration: number;
    /** The songs of the playlist. */
    tracks: Track[];
}
export declare enum ManagerEventTypes {
    Debug = "debug",
    NodeCreate = "nodeCreate",
    NodeDestroy = "nodeDestroy",
    NodeConnect = "nodeConnect",
    NodeReconnect = "nodeReconnect",
    NodeDisconnect = "nodeDisconnect",
    NodeError = "nodeError",
    NodeRaw = "nodeRaw",
    PlayerCreate = "playerCreate",
    PlayerDestroy = "playerDestroy",
    PlayerStateUpdate = "playerStateUpdate",
    PlayerMove = "playerMove",
    PlayerDisconnect = "playerDisconnect",
    QueueEnd = "queueEnd",
    SocketClosed = "socketClosed",
    TrackStart = "trackStart",
    TrackEnd = "trackEnd",
    TrackStuck = "trackStuck",
    TrackError = "trackError",
    SegmentsLoaded = "segmentsLoaded",
    SegmentSkipped = "segmentSkipped",
    ChapterStarted = "chapterStarted",
    ChaptersLoaded = "chaptersLoaded"
}
export interface ManagerEvents {
    [ManagerEventTypes.Debug]: [info: string];
    [ManagerEventTypes.NodeCreate]: [node: Node];
    [ManagerEventTypes.NodeDestroy]: [node: Node];
    [ManagerEventTypes.NodeConnect]: [node: Node];
    [ManagerEventTypes.NodeReconnect]: [node: Node];
    [ManagerEventTypes.NodeDisconnect]: [node: Node, reason: {
        code?: number;
        reason?: string;
    }];
    [ManagerEventTypes.NodeError]: [node: Node, error: Error];
    [ManagerEventTypes.NodeRaw]: [payload: unknown];
    [ManagerEventTypes.PlayerCreate]: [player: Player];
    [ManagerEventTypes.PlayerDestroy]: [player: Player];
    [ManagerEventTypes.PlayerStateUpdate]: [oldPlayer: Player, newPlayer: Player, changeType: PlayerStateUpdateEvent];
    [ManagerEventTypes.PlayerMove]: [player: Player, initChannel: string, newChannel: string];
    [ManagerEventTypes.PlayerDisconnect]: [player: Player, oldChannel: string];
    [ManagerEventTypes.QueueEnd]: [player: Player, track: Track, payload: TrackEndEvent];
    [ManagerEventTypes.SocketClosed]: [player: Player, payload: WebSocketClosedEvent];
    [ManagerEventTypes.TrackStart]: [player: Player, track: Track, payload: TrackStartEvent];
    [ManagerEventTypes.TrackEnd]: [player: Player, track: Track, payload: TrackEndEvent];
    [ManagerEventTypes.TrackStuck]: [player: Player, track: Track, payload: TrackStuckEvent];
    [ManagerEventTypes.TrackError]: [player: Player, track: Track, payload: TrackExceptionEvent];
    [ManagerEventTypes.SegmentsLoaded]: [player: Player, track: Track, payload: SponsorBlockSegmentsLoaded];
    [ManagerEventTypes.SegmentSkipped]: [player: Player, track: Track, payload: SponsorBlockSegmentSkipped];
    [ManagerEventTypes.ChapterStarted]: [player: Player, track: Track, payload: SponsorBlockChapterStarted];
    [ManagerEventTypes.ChaptersLoaded]: [player: Player, track: Track, payload: SponsorBlockChaptersLoaded];
}
export {};
