import Player from "../minecraft/Player";
import NodeStorage from "./NodeStorage";
import LocalEnvironment from "./LocalEnvironment";
import DedicatedServer from "./DedicatedServer";
import { IStatData, IDebugSessionInfo, IProfilerCaptureEvent } from "../debugger/IMinecraftDebugProtocol";
import CreatorTools from "../app/CreatorTools";
import HttpServer from "./HttpServer";
import { IMinecraftStartMessage } from "../app/IMinecraftStartMessage";
import { FileListings } from "./NodeFolder";
import IFolder from "../storage/IFolder";
import { IPackageReference, IWorldSettings } from "../minecraft/IWorldSettings";
import Package from "../app/Package";
import ServerMessage from "./ServerMessage";
import WorldBackupManager from "./WorldBackupManager";
import { IBackupOptions, IBackupResult } from "./IWorldBackupData";
import ManagedWorld from "./ManagedWorld";
import WorldBackup from "./WorldBackup";
export declare const ServerVersionVariants = 5;
export declare enum ServerManagerFeatures {
    all = 0,
    allWebServices = 1,
    basicWebServices = 2,
    dedicatedServerOnly = 3
}
export declare enum ServerType {
    bedrockWindows = 0,
    bedrockLinux = 1,
    bedrockWindowsPreview = 2,
    bedrockLinuxPreview = 3,
    java = 4
}
export interface IServerVersion {
    serverType?: ServerType;
    version?: string;
    versionIndex?: number;
    downloadedPath?: string;
    downloadedIndex?: number;
    downloadPrefix?: string;
}
/**
 * Tracks the provisioning state of a slot folder.
 * Used to avoid unnecessary reprovisioning on stop/start cycles.
 *
 * This is persisted to disk as `slot_context.json` in each slot folder
 * (the "sentinel file") so that context survives server restarts.
 */
export interface ISlotProvisioningInfo {
    /** The source server path used to provision this slot */
    sourceServerPath: string;
    /** When the slot was last provisioned (ISO string when serialized) */
    provisionedAt: Date | string;
    /** The server version string (e.g., "1.21.50.24") */
    version?: string;
    /** UUIDs of deployed behavior packs */
    deployedBehaviorPackIds?: string[];
    /** UUIDs of deployed resource packs */
    deployedResourcePackIds?: string[];
    /** Whether beta APIs experiment is enabled */
    betaApisEnabled?: boolean;
    /**
     * When true, the world is transient - not backed up and reset on each deployment.
     * Useful for development scenarios where you always want a fresh world.
     */
    transientWorld?: boolean;
}
/**
 * Options for slot provisioning.
 */
export interface ISlotProvisioningOptions {
    /** Force reprovisioning even if source hasn't changed */
    forceReprovision?: boolean;
    /**
     * When true, the world is transient - not backed up and cleared on each deployment.
     * Useful for development scenarios where you always want a fresh world.
     */
    transientWorld?: boolean;
}
export default class ServerManager {
    #private;
    dataStorage: NodeStorage;
    runOnce: boolean | undefined;
    maxServerIndex: number;
    primaryServerPort: number;
    backupWorldFileListings: FileListings;
    /**
     * Get the world backup manager.
     */
    get worldBackupManager(): WorldBackupManager | undefined;
    serverVersions: IServerVersion[];
    get isAnyServerRunning(): boolean;
    get creatorTools(): CreatorTools;
    get effectiveAutoSourceServerPath(): string;
    get activeDirectServer(): DedicatedServer;
    get primaryActiveServer(): DedicatedServer;
    /**
     * Get all active servers as an array.
     */
    get activeServers(): DedicatedServer[];
    get features(): ServerManagerFeatures;
    set features(featuresIn: ServerManagerFeatures);
    get onServerOutput(): import("ste-events").IEvent<DedicatedServer, ServerMessage>;
    get onServerError(): import("ste-events").IEvent<DedicatedServer, string>;
    get onServerStarted(): import("ste-events").IEvent<DedicatedServer, string>;
    get onServerRefreshed(): import("ste-events").IEvent<DedicatedServer, string>;
    get onServerStarting(): import("ste-events").IEvent<DedicatedServer, string>;
    get onServerStopped(): import("ste-events").IEvent<DedicatedServer, string>;
    get onServerStopping(): import("ste-events").IEvent<DedicatedServer, string>;
    get onTestStarted(): import("ste-events").IEvent<DedicatedServer, string>;
    get onShutdown(): import("ste-events").IEvent<ServerManager, string>;
    get onTestFailed(): import("ste-events").IEvent<DedicatedServer, string>;
    get onTestSucceeded(): import("ste-events").IEvent<DedicatedServer, string>;
    get onDebugConnected(): import("ste-events").IEvent<DedicatedServer, IDebugSessionInfo>;
    get onDebugDisconnected(): import("ste-events").IEvent<DedicatedServer, string>;
    get onDebugStats(): import("ste-events").IEvent<DedicatedServer, {
        tick: number;
        stats: IStatData[];
    }>;
    get onDebugPaused(): import("ste-events").IEvent<DedicatedServer, string>;
    get onDebugResumed(): import("ste-events").IEvent<DedicatedServer, void>;
    get onProfilerCapture(): import("ste-events").IEvent<DedicatedServer, IProfilerCaptureEvent>;
    get onPlayerConnected(): import("ste-events").IEvent<DedicatedServer, Player>;
    get onPlayerDisconnected(): import("ste-events").IEvent<DedicatedServer, Player>;
    get usePreview(): boolean | undefined;
    set usePreview(newUsePreview: boolean | undefined);
    /**
     * Get the slot prefix used for folder naming.
     * This allows different contexts (MCP, serve, VS Code) to have isolated server slots.
     */
    get slotPrefix(): string;
    /**
     * Set the slot prefix for folder naming.
     * Different contexts should use different prefixes:
     * - "mcp" for MCP command → "mcp0", "mcp1", etc.
     * - "serve" for serve command → "serve0", "serve1", etc.
     * - "vscode" for VS Code extension → "vscode0", "vscode1", etc.
     * - "" (empty) for default/backward compatibility → "slot0", "slot1", etc.
     */
    set slotPrefix(prefix: string);
    /**
     * Gets the folder name for a given slot number, including the context prefix.
     * Examples:
     * - slotPrefix="" → "slot0", "slot1", etc.
     * - slotPrefix="mcp" → "mcp0", "mcp1", etc.
     * - slotPrefix="serve" → "serve0", "serve1", etc.
     * - slotPrefix="vscode" → "vscode0", "vscode1", etc.
     */
    getSlotFolderName(slotNumber: number): string;
    constructor(env: LocalEnvironment, creatorTools: CreatorTools);
    /**
     * Register signal handlers to gracefully shutdown all servers when the process is terminated.
     * This prevents orphaned bedrock_server processes that could hold ports.
     */
    private registerProcessSignalHandlers;
    stopWebServer(reason?: string): Promise<void>;
    shutdown(message: string): Promise<void>;
    ensureHttpServer(port?: number): HttpServer;
    get environment(): LocalEnvironment;
    getRootPath(): string;
    ensureDedicatedServerForPath(name: string, serverPath: string): DedicatedServer;
    stopAllDedicatedServers(): Promise<boolean>;
    private bubblePlayerConnected;
    private bubblePlayerDisconnected;
    /**
     * Handle game events from the dedicated server (e.g., PlayerTravelled, BlockBroken, etc.)
     * and relay them to WebSocket clients.
     */
    private bubbleServerGameEvent;
    private bubbleServerError;
    private bubbleServerOutput;
    private bubbleServerStarted;
    /**
     * Start watching the server's storage folders (world, behavior_packs, resource_packs)
     * for file changes and broadcast notifications to WebSocket clients.
     */
    private startWatchingServerStorage;
    /**
     * Stop watching the server's storage folders when the server stops.
     */
    private stopWatchingServerStorage;
    private bubbleServerRefreshed;
    private bubbleServerStarting;
    private bubbleServerStopping;
    private bubbleServerStopped;
    /**
     * Get the slot number for a given DedicatedServer.
     * Returns 0 if the server is not found in active servers.
     */
    private getSlotForServer;
    /**
     * Push a status update notification via WebSocket.
     * This replaces the need for clients to poll /api/{slot}/status/
     */
    private pushStatusNotification;
    private bubbleTestFailed;
    private bubbleTestStarted;
    private bubbleTestSucceeded;
    private bubbleDebugConnected;
    private bubbleDebugDisconnected;
    private bubbleDebugStats;
    private bubbleDebugPaused;
    private bubbleDebugResumed;
    private bubbleProfilerCapture;
    get effectiveIsUsingPreview(): boolean;
    getLatestVersionInfo(force: boolean): Promise<boolean>;
    static getServerTypeStr(serverType: ServerType): string;
    static getServerTypeFromString(serverVersion: string): ServerType | undefined;
    deployPackCache(): Promise<void>;
    downloadLatestSourceServer(): Promise<boolean>;
    replaceVersion(versionString: string, stub: string): string;
    private static _getSafeVersion;
    private tryDownloadDedicatedServer;
    private ensurePackCacheFolder;
    private ensureSourceServerFolder;
    prepare(force?: boolean): Promise<void>;
    _loadLatestDownloadedSource(): void;
    ensureDirectServer(directServerPath: string): DedicatedServer;
    getBasePortForSlot(slotNumber?: number): number;
    getActiveServer(basePortOrSlot?: number): DedicatedServer;
    /**
     * Get all active slot numbers that have running DedicatedServer instances.
     * Returns an array of slot numbers (0-79).
     */
    getActiveSlots(): number[];
    getHashFromStartInfo(startInfo?: IMinecraftStartMessage): string;
    ensureActiveServer(basePortOrSlot?: number, startInfo?: IMinecraftStartMessage): Promise<DedicatedServer>;
    /**
     * Checks if a slot needs reprovisioning based on source server path changes.
     * Returns true if reprovisioning is needed, false if the slot can be reused as-is.
     */
    needsReprovisioning(slotNumber: number, sourcePath: string): boolean;
    /**
     * Prepares a slot-based runtime server folder.
     *
     * Uses persistent slot-based folder names (e.g., `slot0/`, `slot1/`) instead of
     * timestamp-based names. This keeps the `bedrock_server.exe` path constant,
     * preventing Windows Firewall from prompting on every server start.
     *
     * **Smart Reprovisioning**: If the slot already exists and was provisioned from
     * the same source server path, this method returns quickly without re-doing
     * file operations. This makes stop/start cycles fast.
     *
     * **Backup Before Clean**: If the slot exists but needs reprovisioning (different
     * source version), world data is backed up before any destructive operations.
     * For transient worlds, the world folder is cleared instead of backed up.
     *
     * @param sourcePath - Path to the downloaded source server (e.g., bwv1.21.50.24/)
     * @param slotNumber - The slot number (0-79) for this server instance
     * @param options - Provisioning options (forceReprovision, transientWorld)
     * @returns Object with name and path for the runtime server
     */
    prepareSlotServerPath(sourcePath: string, slotNumber?: number, options?: ISlotProvisioningOptions): Promise<{
        name: string;
        path: string;
        wasReprovisioned: boolean;
    }>;
    /**
     * Saves the slot context/sentinel file to disk.
     * This file records why/how the slot was created so we can detect context changes.
     */
    saveSlotContext(slotNumber: number, slotServerPath: string, info: ISlotProvisioningInfo): void;
    /**
     * Loads the slot context/sentinel file from disk.
     * Returns undefined if the file doesn't exist or is invalid.
     */
    loadSlotContext(slotNumber: number, slotServerPath: string): ISlotProvisioningInfo | undefined;
    /**
     * Extracts the version string from a source server path.
     * E.g., "bwv1.21.50.24/" -> "1.21.50.24"
     */
    extractVersionFromSourcePath(sourcePath: string): string | undefined;
    /**
     * Backs up world data from a slot folder before destructive operations.
     * Uses the centralized WorldBackupManager for backup storage and deduplication.
     * Skips backup if the slot is marked as transient (transientWorld flag).
     */
    backupSlotWorldData(slotNumber: number, slotServerPath: string): Promise<void>;
    /**
     * Clears world data from a slot folder for transient worlds.
     * This resets the world to a fresh state, only keeping level.dat and level_name.txt
     * to preserve world name and seed settings.
     */
    clearSlotWorldData(slotNumber: number, slotServerPath: string): Promise<void>;
    /**
     * @deprecated Use prepareSlotServerPath instead. This method is kept for backwards
     * compatibility but creates timestamp-based folders that cause Windows Firewall prompts.
     */
    prepareTempServerNameAndPath(sourcePath: string): Promise<{
        name: string;
        path: string;
        wasReprovisioned: boolean;
    }>;
    preparePacksAndTemplates(targetPath: string, targetWorldFolder: IFolder, worldSettings: IWorldSettings): Promise<void>;
    addPackageFolders(targetPath: string, pack: Package, packRef: IPackageReference): Promise<void>;
    addWorldTemplate(targetWorldFolder: IFolder, pack: Package): Promise<void>;
    addPackFolderReferences(targetPath: string, folder: IFolder, folderModifier: string, packRefSet: IPackageReference): Promise<void>;
    copyWorldFiles(targetWorldFolder: IFolder, sourceFolder: IFolder): Promise<void>;
    addChildFolderReferences(targetPath: string, loadedFolder: IFolder, folderModifier: string, targetSubFolder: string): void;
    cleanDedicatedServerSymLinkFolder(folder: string, tempServerPath: string): void;
    createSymLinkFolder(targetPath: string, sourcePath: string): void;
    createDedicatedServerSymLinkFolder(sourcePath: string, folder: string, tempServerPath: string): void;
    cleanDedicatedServerSymLinkFile(file: string, tempServerPath: string): void;
    createDedicatedServerFile(sourcePath: string, file: string, tempServerPath: string): void;
    /**
     * Updates a symlink folder for slot-based server provisioning.
     * If the target exists (symlink or directory), it is removed and recreated.
     * This allows updating an existing slot to point to a new source server version.
     */
    updateDedicatedServerSymLinkFolder(sourcePath: string, folder: string, slotServerPath: string): void;
    /**
     * Updates a file for slot-based server provisioning.
     * Overwrites the existing file in place, keeping the same path.
     * This is critical for bedrock_server.exe to avoid Windows Firewall prompts.
     */
    updateDedicatedServerFile(sourcePath: string, file: string, slotServerPath: string): void;
    /**
     * List all managed worlds with their backup information.
     */
    listManagedWorlds(): Promise<ManagedWorld[]>;
    /**
     * Get a managed world by its ID.
     */
    getManagedWorld(worldId: string): Promise<ManagedWorld | undefined>;
    /**
     * Create a new managed world with a unique ID.
     * @param friendlyName Human-readable name for the world
     * @param description Optional description
     * @returns The newly created ManagedWorld
     */
    createManagedWorld(friendlyName: string, description?: string): Promise<ManagedWorld>;
    /**
     * Create a backup of a world from a source folder.
     * @param worldId The ID of the managed world to backup to
     * @param sourceFolder The folder containing the world data to backup
     * @param options Backup options
     * @returns The backup result
     */
    createWorldBackup(worldId: string, sourceFolder: IFolder, options?: IBackupOptions): Promise<IBackupResult>;
    /**
     * Restore a backup to a target folder.
     * @param worldId The ID of the managed world
     * @param timestamp The backup timestamp to restore (or undefined for latest)
     * @param targetFolder The folder to restore to
     */
    restoreWorldBackup(worldId: string, timestamp: number | undefined, targetFolder: IFolder): Promise<void>;
    /**
     * Export a backup as a .mcworld file.
     * @param worldId The ID of the managed world
     * @param timestamp The backup timestamp to export (or undefined for latest)
     * @param outputPath The path to write the .mcworld file to
     */
    exportBackupAsMcWorld(worldId: string, timestamp: number | undefined, outputPath: string): Promise<void>;
    /**
     * Get all backups for a managed world.
     * @param worldId The ID of the managed world
     */
    getWorldBackups(worldId: string): Promise<WorldBackup[]>;
    /**
     * Delete a specific backup.
     * @param worldId The ID of the managed world
     * @param timestamp The backup timestamp to delete
     */
    deleteWorldBackup(worldId: string, timestamp: number): Promise<void>;
    /**
     * Prune old backups for a world, keeping only the most recent ones.
     * @param worldId The ID of the managed world
     * @param keepCount Number of backups to keep (default 10)
     */
    pruneWorldBackups(worldId: string, keepCount?: number): Promise<number>;
    /**
     * Get or create a managed world for a given slot.
     * This creates a mapping between server slots and managed worlds.
     * @param slotNumber The server slot number
     * @param createIfMissing If true, creates a new world if none exists for the slot
     */
    getOrCreateWorldForSlot(slotNumber: number, createIfMissing?: boolean): Promise<ManagedWorld | undefined>;
    register(): void;
}
