import WebSocket from 'isomorphic-ws';

declare const httpFetch: <T>(endpoint: string, url?: string) => Promise<T>;

type Nullable<T> = T | null;
type UserProfile = {
    runs: UserProfileRun[];
};
type UserProfileRun = {
    gameTimeData: Nullable<GameTimeData>;
    personalBestTime: Nullable<string>;
    attemptCount: number;
    displayRun: string;
    run: string;
    uploadTime: string;
    variables: KeyValuePair<string>[];
    user: string;
    personalBest: string;
    finishedAttemptCount: number;
    hasGameTime: boolean;
    timeToSave: number;
    pbId: number;
    totalRunTime: string;
    lastSplitId: number;
    historyFilename: string;
    sessions: Session[];
    gameregion: string;
    sumOfBests: Nullable<string>;
    splitsFile: string;
    emulator: boolean;
    originalRun?: string;
    game: string;
    url: string;
};
type FrontPageRun = {
    gameTimeData: Nullable<GameTimeData>;
    personalBestTime: Nullable<string>;
    status: string;
    displayRun: string;
    attemptCount: number;
    run: string;
    user: string;
    personalBest: string;
    hasGameTime: boolean;
    originalRun: string;
    game: string;
    url: string;
};
type GameTimeData = {
    sessions: Session[];
    personalBest: string;
    personalBestTime: Nullable<string>;
    history: string;
    stdDev: number;
    timeToSave: number;
    sumOfBests: Nullable<string>;
};
type Session = {
    startedAt: string;
    runIds: RunIds[];
    finishedRuns: string[];
    endedAt: string;
};
type RunHistory = {
    runs: Run[];
    splits: SplitHistory[];
    sessions: Session[];
    meta: HistoryMeta;
};
type Run = {
    splits: Split[];
    time: string;
    duration: string;
    startedAt: string;
    endedAt: string;
};
type RunIds = {
    first: number;
    last: number;
};
type Split = {
    splitTime: string;
    totalTime: string;
};
type SplitHistory = {
    single: AdvancedSplitInfo;
    total: AdvancedSplitInfo;
    name: string;
    icon: string;
    values: number[];
    valuesTotal: number[];
};
type AdvancedSplitInfo = {
    time: string;
    bestPossibleTime: Nullable<string>;
    bestAchievedTime: Nullable<string>;
    averageTime: string;
    stdDev: string;
    alternative: AlternativeSplitInfo[];
};
type AlternativeSplitInfo = {
    name: string;
    time: string;
};
type HistoryMeta = {
    totalRunTime: string;
    pbId: number;
};
type GameResult = {
    image: string;
    categories: Category[];
    display: string;
    status: string;
    sort: number;
    game: string;
};
type Category = {
    gameTimePb: Nullable<string>;
    bestTime: string;
    gameTime: boolean;
    display: string;
    bestTimeUser: string;
    category: string;
    totalRunTime: number;
    bestGameTimeUser: string;
};
type Game = {
    data: {
        game: GameDetails;
    };
    stats: GameStats;
};
type GameDetails = {
    alias: string;
    active: boolean;
    image: string;
    display: string;
    game: string;
};
type GameStats = {
    userData: KeyValuePair<string>[];
    gameLeaderboard: Leaderboard;
    categoryLeaderboards: Leaderboard[];
    statsGameTime: {
        userData: KeyValuePair<string>[];
        gameLeaderboard: Leaderboard;
        categoryLeaderboards: Leaderboard[];
    };
    global: GameDetails;
};
type KeyValuePair<T> = {
    [key: string]: T;
};
type Leaderboard = {
    uploadLeaderboard: LeaderboardDetails[];
    attemptCountLeaderboard: LeaderboardDetails[];
    finishedAttemptCountLeaderboard: LeaderboardDetails[];
    totalRunTimeLeaderboard: LeaderboardDetails[];
    recentRuns: LeaderboardRecentRun[];
    completePercentageLeaderboard: LeaderboardDetails[];
    categoryName?: string;
    categoryNameDisplay?: string;
    stats: LeaderboardStats;
};
type LeaderboardDetails = {
    username: string;
    stat: number;
    meta: Nullable<string>;
    game: string;
    category: string;
    url: string;
};
type LeaderboardStats = {
    uploadCount: number;
    attemptCount: number;
    finishedAttemptCount: number;
    totalRunTime: number;
    completePercentage: number;
};
type LeaderboardRecentRun = {
    achievedAt: string;
    time: string;
    username: string;
    category: string;
};
type FrontPageData = {
    runs: FrontPageRun[];
    gamestats: GameResult[];
};
type LiveWebSocketResponse = {
    user: string;
    run: LiveRun;
    type: string;
};
type WebSocketEvent<T> = (data?: T) => void;
type LiveRun = {
    game: string;
    splits: LiveSplit[];
    bestPossible: Nullable<number>;
    importance: Nullable<number>;
    sob: Nullable<number>;
    delta: number;
    startedAt: string;
    platform: string;
    gameTime: false;
    events: LiveRunEvent[];
    previousRun: Nullable<LiveRun>;
    variables: KeyValuePair<string>[];
    currentSplitIndex: number;
    runPercentage: number;
    currentlyStreaming: boolean;
    currentPrediction: number;
    picture: string;
    currentTime: 0;
    emulator: false;
    pb: Nullable<number>;
    hasReset: boolean;
    currentSplitName: string;
    insertedAt: number;
    endedAt: string;
    removeAt: number;
    gameData: UserProfileRun;
    gameImage: string;
    region: string;
    category: string;
    user: string;
};
type LiveRunEvent = {
    game: string;
    data: {
        splitName?: string;
        newGold?: number;
        previousGold?: number;
        delta?: number;
        finishedSplitAttemptCount?: number;
        personalBest?: Nullable<number>;
        expectedEndTime?: Nullable<number>;
        achievedTime?: number;
        targetTime?: number;
        pbSplitTime?: string;
        expectedSplitTime?: number;
        bestSplitTime?: string;
    };
    name: string;
    description: string;
    time: string;
    type: string;
    category: string;
    username: string;
};
type LiveSplit = {
    average: Nullable<number>;
    top90Single: Nullable<number>;
    pbSplitTime: Nullable<number>;
    deltaToPredicted: Nullable<number>;
    recentCompletionsSingle: number[];
    bestPossible: Nullable<number>;
    consistency: Nullable<number>;
    top90Total: Nullable<number>;
    single: AdvancedSplitInfo;
    total: AdvancedSplitInfo;
    top10Total: Nullable<number>;
    attemptsFinished: number;
    top10Single: Nullable<number>;
    name: string;
    comparisons: KeyValuePair<Nullable<number>>;
    predictedSingleTime: Nullable<number>;
    recentCompletionsTotal: number[];
    attemptsStarted: number;
    splitTime: Nullable<number>;
};

declare class LiveWebSocket {
    private _websocket;
    /**
     * Used to fire events when the WebSocket connection opens. There's no difference between
     * this and the method provided by WebSocket - this is only here for your convenience.
     */
    onOpen: WebSocketEvent<void> | undefined;
    /**
     * Used to fire events when the WebSocket connection closes. There's no difference between
     * this and the method provided by WebSocket - this is only here for your convenience.
     */
    onClose: WebSocketEvent<void> | undefined;
    /**
     * Used to handle a message received by the WebSocket connection.
     * The only difference between using this and the methods provided by WebSocket
     * is this method will ensure the WebSocket response is parsed and typed properly.
     * @example
     * const ws = new LiveWebSocket();
     *
     * ws.onMessage = (data) => {
     *   console.log(data.user); // Data is automatically parsed and assigned the proper type
     * }
     */
    onMessage: WebSocketEvent<LiveWebSocketResponse> | undefined;
    /**
     * Used to fire events when the WebSocket connection encounters an error. There's no difference between
     * this and the method provided by WebSocket - this is only here for your convenience.
     */
    onError: WebSocketEvent<WebSocket.ErrorEvent> | undefined;
    /**
     * Initializes a new instance of the LiveWebSocket object
     * @param {string} [username] Username to listen to
     */
    constructor(username?: string);
    /**
     * Returns the current WebSocket connection
     */
    get connection(): WebSocket;
}

/**
 * Gets front page data
 * @returns FrontPageData
 */
declare const getFrontPageData: () => Promise<FrontPageData>;

/**
 * Gets the run history, which is used to populate the run detail page.
 * See: https://github.com/therungg/api-docs#user-runs
 * @param historyFileName
 * @returns RunHistory
 */
declare const getHistory: (historyFileName: string) => Promise<RunHistory>;

/**
 * Gets all live runs.
 * @deprecated do not rely on this function, as it will likely be deprecated in the future
 * @returns LiveRun[]
 */
declare const getAllLiveRuns: () => Promise<LiveRun[]>;

/**
 * Gets a live run
 * @param username
 * @returns LiveRun
 */
declare const getLiveRun: (username: string) => Promise<LiveRun>;

/**
 * Gets a user profile.
 * @param username
 * @returns UserProfile
 */
declare const getUserProfile: (username: string) => Promise<UserProfile>;

/**
 * Gets list of all games
 * @returns GameResult[]
 */
declare const getAllGames: () => Promise<GameResult[]>;

/**
 * Gets a game's details by its name.
 * @param game Game name
 * @returns Game
 */
declare const getGame: (game: string) => Promise<Game>;

export { AdvancedSplitInfo, AlternativeSplitInfo, Category, FrontPageData, FrontPageRun, Game, GameDetails, GameResult, GameStats, GameTimeData, HistoryMeta, KeyValuePair, Leaderboard, LeaderboardDetails, LeaderboardRecentRun, LeaderboardStats, LiveRun, LiveRunEvent, LiveSplit, LiveWebSocket, LiveWebSocketResponse, Nullable, Run, RunHistory, RunIds, Session, Split, SplitHistory, UserProfile, UserProfileRun, WebSocketEvent, getAllGames, getAllLiveRuns, getFrontPageData, getGame, getHistory, getLiveRun, getUserProfile, httpFetch };
