import { type RequestOptions, type Response } from "@adobe/fetch";
import type { AccessBootstrapConfig, AccessControllerConfig, AccessDeviceConfig, AccessDeviceConfigPayload, AccessDoorConfig, AccessFloorConfig } from "./access-types.js";
import type { AccessLogging } from "./access-logging.js";
import { EventEmitter } from "node:events";
/**
 * 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 address;
    private apiErrorCount;
    private apiLastSuccess;
    private events;
    private eventsTimer;
    private fetch;
    private headers;
    private _isAdminUser;
    private log;
    private password;
    private username;
    private apikey;
    /**
     * 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;
    /**
     * 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 apikey   - Apikey for 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);
     * };
     * ```
     */
    loginapi(address: string, apikey: string): Promise<boolean>;
    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<DeviceType | null>;
    /**
     * 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, 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       - Requested endpoint type. Valid types are `livestream` and `talkback`.
     * @param options   - Parameters to pass on for the endpoint request.
     * @param logErrors - Log errors that aren't already accounted for and handled, rather than failing silently. Defaults to `true`.
     *
     * @returns Returns a promise that will resolve to a Response object successful, and `null` otherwise.
     *
     * @remarks This method should be used when direct access to the Access controller is needed, or when this library doesn't have a needed method to access
     *   controller capabilities.
     */
    retrieve(url: string, options?: RequestOptions, logErrors?: boolean): Promise<Response | null>;
    private _retrieve;
    private logRetry;
    /**
     * 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(): AccessControllerConfig | null;
    /**
     * Access the Access controller bootstrap JSON.
     *
     * @returns Returns the bootstrap JSON if the Access controller has been bootstrapped, `null` otherwise.
     */
    get bootstrap(): AccessBootstrapConfig | null;
    /**
     * 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(): AccessDeviceConfig[] | null;
    /**
     * 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(): AccessDoorConfig[] | null;
    /**
     * 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(): AccessFloorConfig[] | null;
    /**
     * 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 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;
}
