import type { AccessBootstrapConfig, AccessControllerConfig, AccessDeviceConfig, AccessDeviceConfigPayload, AccessDoorConfig, AccessFloorConfig, Nullable } from "./access-types.js";
import { type Dispatcher } from "undici";
import type { AccessLogging } from "./access-logging.js";
import { EventEmitter } from "node:events";
export type RequestOptions = {
    dispatcher?: Dispatcher;
} & Omit<Dispatcher.RequestOptions, "origin" | "path">;
/**
 * Options to tailor the behavior of {@link AccessApi.retrieve}.
 *
 * @property {boolean} [logErrors=true] - Log errors. Defaults to `true`.
 * @property {number} [timeout=3500] - Amount of time, in milliseconds, to wait for the Access controller to respond before timing out. Defaults to `3500`.
 */
export interface RetrieveOptions {
    logErrors?: boolean;
    timeout?: number;
}
/**
 * The direct UniFi Access API is partially documented through an officially supported public API that Ubiquiti has released. However, this API also has certain
 * constraints and limitations such as lacking the ability to change the settings on an Access device. The full native API has been reverse engineered mostly through
 * trail and error with the Access web interface as well as insight from the public API.
 *
 * Here's how the UniFi Access API works:
 *
 * 1. {@link login | Login} to the UniFi Access controller and acquire security credentials for further calls to the API.
 *
 * 2. Enumerate the list of UniFi Access devices by calling the {@link bootstrap} property. This contains everything you would want to know about the devices attached to
 *    this particular UniFi Access controller. Information about the Access controller can be accessed through the {@link controller} property.
 *
 * 3. Listen for `message` events emitted by {@link AccessApi} containing all Access controller events, in realtime. They are delivered as
 *    {@link access-types.AccessEventPacket} packets, containing the event-specific details.
 *
 * Those are the basics that gets us up and running.
 */
export declare class AccessApi extends EventEmitter {
    private _bootstrap;
    private _controller;
    private _devices;
    private _doors;
    private _floors;
    private _isAdminUser;
    private _isThrottled;
    private address;
    private apiErrorCount;
    private apiLastSuccess;
    private dispatcher?;
    private events;
    private eventsTimer;
    private headers;
    private log;
    private password;
    private username;
    /**
     * Create an instance of the UniFi Access API.
     *
     * @param log - Logging functions to use.
     *
     * @defaultValue `none` - Logging will be done to stdout and stderr.
     */
    constructor(log?: AccessLogging);
    /**
     * Execute a login attempt to the UniFi Access API.
     *
     * @param address - Address of the UniFi Access controller, expressed as an FQDN or IP address.
     * @param username   - Username to use when logging into the controller.
     * @param password   - Password to use when logging into the controller.
     *
     * @returns Returns a promise that will resolve to `true` if successful and `false` otherwise.
     *
     * @remarks A `login` event will be emitted each time this method is called, with the result of the attempt as an argument.
     *
     * @example
     * Login to the Access controller. You can selectively choose to either `await` the promise that is returned by `login`, or subscribe to the `login` event.
     *
     * ```ts
     * import { AccessApi } from "unifi-access";
     *
     * // Create a new Access API instance.
     * const ufp = new AccessApi();
     *
     * // Set a listener to wait for the login event to occur.
     * ufp.once("login", (successfulLogin: boolean) => {
     *
     *   // Indicate if we are successful.
     *   if(successfulLogin) {
     *
     *     console.log("Logged in successfully.");
     *     process.exit(0);
     *   }
     * });
     *
     * // Login to the Access controller.
     * if(!(await ufa.login("access-controller.local", "username", "password"))) {
     *
     *   console.log("Invalid login credentials.");
     *   process.exit(0);
     * };
     * ```
     */
    login(address: string, username: string, password: string): Promise<boolean>;
    private loginController;
    private bootstrapController;
    private launchEventsWs;
    /**
     * Retrieve the bootstrap JSON from a UniFi Access controller.
     *
     * @returns Returns a promise that will resolve to `true` if successful and `false` otherwise.
     *
     * @remarks A `bootstrap` event will be emitted each time this method is successfully called, with the AccessToplogyConfig JSON as an argument. As a
     * convenience, the {@link devices}, {@link doors}, and {@link floors} properties will be populated as well.
     *
     * @example
     * Retrieve the bootstrap JSON. You can selectively choose to either `await` the promise that is returned by `getBootstrap`, or subscribe to the `bootstrap` event.
     *
     * ```ts
     * import { AccessApi, AccessDeviceConfig } from "unifi-access";
     * import util from "node:util";
     *
     * // Create a new Access API instance.
     * const ufa = new AccessApi();
     *
     * // Set a listener to wait for the bootstrap event to occur.
     * ufa.once("bootstrap", (bootstrapJSON: AccessDeviceConfig) => {
     *
     *   // Once we've bootstrapped the Access controller, output the bootstrap JSON and we're done.
     *   process.stdout.write(util.inspect(bootstrapJSON, { colors: true, depth: null, sorted: true }) + "\n", () => process.exit(0));
     * });
     *
     * // Login to the Access controller.
     * if(!(await ufa.login("access-controller.local", "username", "password"))) {
     *
     *   console.log("Invalid login credentials.");
     *   process.exit(0);
     * };
     *
     * // Bootstrap the controller. It will emit a message once it's received the bootstrap JSON, or you can alternatively wait for the promise to resolve.
     * if(!(await ufa.getBootstrap())) {
     *
     *   console.log("Unable to bootstrap the Access controller.");
     *   process.exit(0);
     * }
     * ```
     *
     * Alternatively, you can access the bootstrap JSON directly through the {@link bootstrap} accessor:
     *
     * ```ts
     * import { AccessApi } from "unifi-access";
     * import util from "node:util";
     *
     * // Create a new Access API instance.
     * const ufa = new AccessApi();
     *
     * // Login to the Access controller.
     * if(!(await ufa.login("access-controller.local", "username", "password"))) {
     *
     *   console.log("Invalid login credentials.");
     *   process.exit(0);
     * };
     *
     * // Bootstrap the controller.
     * if(!(await ufa.getBootstrap())) {
     *
     *   console.log("Unable to bootstrap the Access controller.");
     *   process.exit(0);
     * }
     *
     * // Once we've bootstrapped the Access controller, access the bootstrap JSON through the bootstrap accessor and we're done.
     * process.stdout.write(util.inspect(ufa.bootstrap, { colors: true, depth: null, sorted: true }) + "\n", () => process.exit(0));
     * ```
     *
     */
    getBootstrap(): Promise<boolean>;
    /**
     * Send an unlock command to the Access controller.
     *
     * @param device    - Access device.
     * @param duration  - Unlock interval in minutes.
     *
     * @returns Returns `true` if successful, `false` otherwise.
     *
     * @remarks If `duration` is not specified, a standard unlock request will be sent to the Access controller which will unlock for 2 seconds. Valid values for duration
     * are `Infinity` - remain unlocked until reset, `0` - reset lock to secure state, `duration` - number of minutes.
     */
    unlock(device: AccessDeviceConfig, duration?: number): Promise<boolean>;
    /**
     * Update an Access device's configuration on the UniFi Access controller.
     *
     * @typeParam DeviceType - Generic for any known Access device type.
     *
     * @param device  - Access device.
     * @param payload - Device configuration payload to upload, usually a subset of the device-specific configuration JSON.
     *
     * @returns Returns a promise that will resolve to the updated device-specific configuration JSON if successful, and `null` otherwise.
     *
     * @remarks Use this method to change the configuration of a given Access device or controller. It requires the credentials used to login to the Access API
     *   to have administrative privileges for most settings.
     */
    updateDevice<DeviceType extends AccessDeviceConfig>(device: DeviceType, payload: AccessDeviceConfigPayload): Promise<Nullable<DeviceType>>;
    /**
     * Utility method that generates a nicely formatted device information string.
     *
     * @param device     - Access device.
     * @param name       - Optional name for the device. Defaults to the device type (e.g. `UA G2 Pro Black`).
     * @param deviceInfo - Optionally specify whether or not to include the IP address and MAC address in the returned string. Defaults to `false`.
     *
     * @returns Returns the Access device name in the following format: <code>*Access device name* [*Access device type*] (address: *IP address* mac: *MAC address*)</code>.
     *
     * @remarks The example above assumed the `deviceInfo` parameter is set to `true`.
     */
    getDeviceName(device: AccessDeviceConfig, name?: string | undefined, deviceInfo?: boolean): string;
    /**
     * Utility method that generates a combined, nicely formatted device and controller string.
     *
     * @param device - Access device.
     *
     * @returns Returns the Access device name in the following format:
     *   <code>*Access controller name* [*Access controller type*] *Access device name* [*Access device type*]</code>.
     */
    getFullName(device: AccessDeviceConfig): string;
    /**
     * Terminate any open connection to the UniFi Access API.
     */
    reset(): void;
    /**
     * Clear the login credentials and terminate any open connection to the UniFi Access API.
     */
    logout(): void;
    /**
     * Execute an HTTP fetch request to the Access controller.
     *
     * @param url       - Full URL to request (e.g., `https://192.168.1.1/proxy/access/api/v2/devices/topologyv4`)
     * @param options   - Parameters to pass on for the endpoint request.
     * @param retrieveOptions - Additional options for error handling and timeouts
     *
     * @returns Promise resolving to the Response object, or `null` on failure.
     *
     * @remarks
     * This method provides direct access to the Protect controller API for advanced use cases not covered by the built-in methods. It handles:
     *
     * - Authentication and session management
     * - Automatic retry with exponential backoff
     * - Error logging and throttling
     * - CSRF token management
     *
     * The `options` parameter extends [Undici's RequestOptions](https://undici.nodejs.org/#/docs/api/Dispatcher.md?id=parameter-requestoptions), providing full control
     * over the HTTP request.
     */
    retrieve(url: string, options?: RequestOptions, retrieveOptions?: RetrieveOptions): Promise<Nullable<Dispatcher.ResponseData<unknown>>>;
    private _retrieve;
    private logRetry;
    responseOk(code?: number): boolean;
    /**
     * Return an API endpoint for the requested endpoint type.
     *
     * @param endpoint - Requested endpoint type.
     *
     * @returns Returns a URL to the requested endpoint if successful, and an empty string otherwise.
     *
     * @remarks Valid API endpoints are `bootstrap`, `device`, `login`, `self`, and `websocket`.
     */
    getApiEndpoint(endpoint: string): string;
    /**
     * Access the Access controller information JSON.
     *
     * @returns Returns the controller information JSON if the Access controller has been bootstrapped, `null` otherwise.
     */
    get controller(): Nullable<AccessControllerConfig>;
    /**
     * Access the Access controller bootstrap JSON.
     *
     * @returns Returns the bootstrap JSON if the Access controller has been bootstrapped, `null` otherwise.
     */
    get bootstrap(): Nullable<AccessBootstrapConfig>;
    /**
     * Access the Access controller list of devices.
     *
     * @returns Returns an array of all the devices from all the UniFi Access hubs associated with this controller, `null` otherwise.
     */
    get devices(): Nullable<AccessDeviceConfig[]>;
    /**
     * Access the Access controller list of doors.
     *
     * @returns Returns an array of all the doors from all the UniFi Access hubs associated with this controller, `null` otherwise.
     */
    get doors(): Nullable<AccessDoorConfig[]>;
    /**
     * Access the Access controller list of floors.
     *
     * @returns Returns an array of all the floors from all the UniFi Access hubs associated with this controller, `null` otherwise.
     */
    get floors(): Nullable<AccessFloorConfig[]>;
    /**
     * Utility method that returns whether the credentials that were used to login to the Access controller have administrative privileges or not.
     *
     * @returns Returns `true` if the logged in user has administrative privileges, `false` otherwise.
     */
    get isAdminUser(): boolean;
    /**
     * Utility method that returns whether our connection to the Access controller is currently throttled or not.
     *
     * @returns Returns `true` if the API has returned too many errors and is now throttled for a period of time, `false` otherwise.
     *
     * @category Utilities
     */
    get isThrottled(): boolean;
    /**
     * Utility method that returns a nicely formatted version of the Access controller name.
     *
     * @returns Returns the Access controller name in the following format:
     *   <code>*Access controller name* [*Access controller type*]</code>.
     */
    get name(): string;
}
