import type { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies";
import type { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
import type { NextRequest, NextResponse } from "next/server";
export interface NextBungieAuth {
    /**
     * The single handler for Bungie OAuth. Wraps the individual handlers.
     */
    catchAllHandler: {
        POST: (request: NextRequest) => Promise<NextResponse>;
        GET: (request: NextRequest) => Promise<NextResponse>;
    };
    /**
     * The Next.js API routes for Bungie OAuth for my fain grained control.
     * These routes should be destructured and exported individually in a route handler file.
     */
    handlers: {
        /**
         * Redirects the user to the Bungie OAuth page.
         */
        authorizeGET: (request: NextRequest) => Promise<NextResponse>;
        /**
         * Deauthorizes the user's Bungie OAuth session.
         */
        deauthorizePOST: (request: NextRequest) => Promise<NextResponse<NextBungieAuthSessionResponse>>;
        /**
         * Handles the callback from the Bungie OAuth page.
         */
        callbackGET: (request: NextRequest) => Promise<never>;
        /**
         * Retrieves the user's Bungie OAuth session.
         */
        sessionGET: (request: NextRequest) => Promise<NextResponse<NextBungieAuthSessionResponse>>;
        /**
         * Refreshes the user's Bungie OAuth session.
         */
        refreshPOST: (request: NextRequest) => Promise<NextResponse<NextBungieAuthSessionResponse>>;
    };
    /**
     * Server-side helper functions for managing the session in server-side logic
     */
    serverSideHelpers: {
        /**
         * Clears the session cookie
         */
        clearServerSession: (cookies: ReadonlyRequestCookies) => void;
        /**
         * Requests new tokens from the Bungie API.
         */
        requestNewTokens: (grantType: "authorization_code" | "refresh_token", value: string, cookies: ReadonlyRequestCookies) => Promise<BungieTokenResponse>;
        /**
         * Updates the server session with new tokens.
         */
        updateServerSession: (tokens: BungieTokenResponse, iat: Date, cookies: ReadonlyRequestCookies) => void;
        /**
         * Synchronously retrieves the current server session from the request cookies.
         * Does not refresh the session, so it may be expired.
         */
        getServerSession: (cookies: ReadonlyRequestCookies) => NextBungieAuthSessionResponse;
        /**
         * Retrieves the current server session from the cookies and refreshes.
         * Can only be called from an API route or a server-action.
         */
        getRefreshedServerSession: (cookies: ReadonlyRequestCookies) => Promise<{
            session: NextBungieAuthSessionResponse;
            message: string;
        }>;
    };
}
export type NextBungieAuthConfigRequiredKeys = "clientId" | "clientSecret" | "generateState";
/**
 * Configuration options for NextBungieAuth.
 */
export interface NextBungieAuthConfig {
    /**
     * The client ID for Bungie OAuth.
     */
    clientId: string;
    /**
     * The client secret for Bungie OAuth.
     */
    clientSecret: string;
    /**
     * The time in seconds before the access token expires when calls to the session
     * endpoint will refresh the session.
     *
     * Calls to the session endpoint without `force=true` will not refresh the session if
     * the access token expires in greater than this time.
     *
     * Defaults to 300 seconds (5 minutes).
     */
    sessionRefreshGracePeriod: number;
    /**
     * The name of the base cookie. Defaults to `__next-bungie-auth`.
     */
    baseCookieName: string;
    /**
     * Optional cookie options for setting the response cookie.
     * Defaults to ```{
          httpOnly: true,
          secure: true,
          sameSite: "lax"
        }```
     */
    cookieOptions: Partial<Omit<ResponseCookie, "expires">>;
    /**
     * Function to generate a state for the OAuth request.
     * @param request - The NextRequest object.
     * @returns The state string.
     */
    generateState: (request: NextRequest) => string;
    /**
     * Function to make HTTP request given the parameters.
     * Defaults to a fetch request using the native fetch API to the Bungie API.
     *
     * @returns A promise that resolves to the Bungie token response.
     * @throws BungieAuthorizationError | Error
     */
    tokenHttp: (params: {
        clientId: string;
        clientSecret: string;
        grantType: "authorization_code" | "refresh_token";
        grantKey: "code" | "refresh_token";
        value: string;
    }) => Promise<Response>;
    /**
     * During the authorization request, this function generates the callback URL cookie
     * from the request object.
     *
     * Defaults to a function that returns the `callback_url` query parameter
     * or the referrer header if the query parameter is not present.
     *
     * @param request The authorize request object.
     * @returns The value for the callback URL cookie, or null if no callback URL is present.
     */
    generateCallbackUrlCookie: (request: NextRequest) => string | null;
    /**
     * After a successful authorization, this function generates the base callback URL from
     * the request object and the callback URL cookie.
     *
     * @param request The callback request object coming from bungie.net.
     * @param callbackUrlCookie The value of the callback URL cookie.
     * @returns The url to redirect the user to after authorization.
     */
    generateCallbackUrl: (request: NextRequest, callbackUrlCookie: string | null) => string;
    /**
     * After an error occurs during the authorization process, this function generates the
     * callback URL with the error type.
     *
     * @param request The request object coming from bungie.net.
     * @param errorType The type of error that occurred.
     * @param callbackUrlCookie The value of the callback URL cookie.
     * @returns
     */
    generateErrorCallbackUrl: (request: NextRequest, errorType: "state_mismatch" | "token_error", callbackUrlCookie: string | null) => string;
    /**
     * Callback which is called when the user attempts to authorize.
     */
    onAuthorize?: () => void;
    /**
     * Callback which is called when the user signs in.
     */
    onSignIn?: (bungieMembershipId: string) => void;
    /**
     * Callback which is called when the user signs out.
     */
    onSignOut?: (bungieMembershipId: string) => void;
    /**
     * Callback which takes in the result of the request and logs it.
     */
    logRequest: (path: "authorize" | "deauthorize" | "callback" | "session" | "refresh", status: "success" | "error" | "info" | "warn", message: string) => void;
}
export interface BungieTokenResponse {
    access_token: string;
    token_type: "Bearer";
    expires_in: number;
    refresh_token: string;
    refresh_expires_in: number;
    membership_id: string;
}
/**
 * The data returned from the session API route.
 *
 * Dates are in seconds since epoch`.
 */
export interface NextBungieAuthSessionData {
    bungieMembershipId: string;
    accessToken: string;
    accessTokenExpiresAt: string;
}
export interface NextBungieAuthSaleSessionData {
    bungieMembershipId: string;
}
export type NextBungieAuthSessionResponse = {
    status: "expired" | "unauthorized" | "error";
    data: null;
} | {
    status: "stale" | "disabled";
    data: NextBungieAuthSaleSessionData;
} | {
    status: "authorized";
    data: NextBungieAuthSessionData;
};
/**
 * Options for the BungieSessionProvider.
 */
export interface BungieSessionProviderParams {
    children: React.ReactNode;
    initialSession?: NextBungieAuthSessionResponse;
    /**
     * The path to the session API route.
     * @default "/api/auth/session"
     */
    sessionPath?: string;
    /**
     * The path to the refresh session API route.
     * @default "/api/auth/refresh"
     */
    refreshPath?: string;
    /**
     * The path to the deauthorize API route.
     * @default "/api/auth/signout"
     */
    deauthorizePath?: string;
    /**
     * When enabled, the session will automatically
     * refresh when the access token is about to expire.
     * @default true
     */
    enableAutomaticRefresh?: boolean;
    /**
     * When `enableAutomaticRefresh` is enabled and this argument
     * is set to true, the session will refresh even when the tab is in the background.
     * @default true
     */
    refreshInBackground?: boolean;
    /**
     * The time in seconds before the access token expires when calls to the session
     * endpoint will refresh the session.
     * @default 30_000 // (30 seconds)
     */
    timeBeforeRefresh?: number;
    /**
     * The min interval in milliseconds between automatic session refreshes.
     * @default 15_000 // (15 seconds)
     */
    refreshRateLimit?: number;
    /**
     * Handler errors that occur during the client-side session refresh.
     */
    onError?: (error: Error, type: "client" | "server" | "network") => void;
    /**
     * A custom fetch function to use for the client-side session refresh.
     */
    fetchOverride?: typeof fetch;
}
/**
 * Return type for the `useBungieSession` hook.
 */
export type BungieSession = BungieSessionState & {
    /**
     * Refreshes the session. If `force` is false (default), the session will only refresh from bungie.net
     * when expired or inside the grace period.
     */
    refresh: (force?: boolean) => void;
    /**
     * Logs the user out by removing the session cookie.
     */
    kill: () => void;
};
/**
 * The state of the Bungie session. It is a discriminated union type to allow type narrowing.
 *
 * A session can be in one of the following states:
 * - `pending` - The session is being fetched.
 * - `stale` - The session is stale, meaning there is no auth token but the data is available.
 * - `authorized` - The session is authorized and the data is available.
 * - `unauthorized` - There is no session and the data is null.
 * - `unavailable` - The session is unavailable at the moment and the data is available or stale.
 */
export type BungieSessionState = ({
    status: "pending";
    isPending: true;
    isFetching: true;
    isError: false;
    error: undefined;
    data: null;
} | {
    status: "stale";
    isPending: true;
    isFetching: boolean;
    isError: false;
    error: undefined;
    data: null | NextBungieAuthSaleSessionData;
} | {
    status: "authorized";
    isPending: false;
    isFetching: boolean;
    isError: boolean;
    data: NextBungieAuthSessionData;
} | {
    status: "unauthorized";
    isPending: false;
    isFetching: boolean;
    isError: boolean;
    data: null;
} | {
    status: "unavailable";
    isPending: false;
    isFetching: boolean;
    isError: true;
    data: NextBungieAuthSaleSessionData;
}) & ({
    isError: true;
    error: "bungie-api-offline" | "network" | "server" | "client";
} | {
    isError: false;
    error: undefined;
});
