import { RVDashboardDataSource } from "./sdk-model/AbstractClasses/RVDashboardDataSource";
import { RVDataSourceItem } from "./sdk-model/AbstractClasses/RVDataSourceItem";
import { IncomingMessage, RequestListener } from 'http';
import { IDashboardExporter } from "./exporter/exporter";
import { IRVUserContext } from "./IRVUserContext";
import { Readable } from "stream";
import { RVDataModelField, RVDataModelCalculatedField, RVDataModelMeasure } from "./dataModel/dataModelTypes";

export { IDashboardExporter} from "./exporter/exporter";
export { IDashboardTheme} from "./exporter/DashboardTheme";
export { IRVUserContext } from "./IRVUserContext";

export * from "./exporter/ExportOptions";
export * from "./sdk-model/rvDataSourceExports"
export * from "./dataModel/dataModelTypes"

/**
 * Concrete implementation of {@link IRVUserContext} that carries a user ID
 * and an arbitrary properties map through the request pipeline.
 */
export declare class RVUserContext implements IRVUserContext {
    /**
     * @param userId     Unique identifier for the current user.
     * @param properties Arbitrary key/value pairs available to provider callbacks.
     */
    constructor(userId: string, properties: Map<string, Object>);

    /** Unique identifier for the current user. */
    get userId(): string;
    /** Arbitrary key/value pairs available to provider callbacks. */
    get properties(): Map<string, Object>;
}

/**
 * Base interface representing credentials to connect to a given data source.
 */
export declare interface IRVDataSourceCredential {
}

/**
 * The class used to represent domain/user/password credentials, required to connect to all data bases (MS SQL, MySQL, etc)
 * and some other data sources (REST API for example).
 */
export declare class RVUsernamePasswordDataSourceCredential implements IRVDataSourceCredential {
    /**
     * Creates credentials with the specified attributes.
     * @param userName User name.
     * @param password Password.
     * @param domain   Domain.
     */
    constructor(userName: string, password: string, domain?: string);
    /** User name. */
    get userName(): string;
    /** Password. */
    get password(): string;
    /** Domain. */
    get domain(): string | null;
}

/**
 * The class used to represent Bearer (aka 'Token') authentication.
 */
export declare class RVBearerTokenDataSourceCredential implements IRVDataSourceCredential {
    /**
     * Creates credentials with the specified attributes.
     * @param token  Required. This is usually the access token resulting from an OAuth authentication process.
     *               The provided token is expected to be valid (not expired). If the caller's available token is expired or
     *               is about to expire, it is the caller's responsibility to perform a OAuth refresh request in order to get
     *               a fresh access token to use as a parameter for this constructor.
     * @param userId Required. A string that uniquely identifies the user associated with this credentials.
     */
    constructor(token: string, userId?: string);
    /** The bearer token. */
    get token(): string;
    /** The user identifier associated with this credentials. */
    get userId(): string | null;
}

/**
 * The class used to represent authentication using headers (including cookies), supported only by Web Resource and REST API data sources.
 * When sending HTTP requests to get data for the data source, the specified headers will be included.
 */
export declare class RVHeadersDataSourceCredentials implements IRVDataSourceCredential {
    /** Creates an empty headers credentials object, you can use {@link addHeader} to add headers. */
    constructor();
    /**
     * Constructor used to indicate the headers that should be included in data requests.
     * @param headers A map with the headers to send, supports only single-valued headers.
     */
    constructor(headers:Map<string, string>);
    /**
     * Helper constructor to create a headers credentials with a single header, you can add additional headers with {@link addHeader}.
     * @param singleHeaderName  Header name, it will be ignored if null.
     * @param singleHeaderValue Header value, it will be ignored if null.
     */
    constructor(singleHeaderName:string, singleHeaderValue:string);
    /** The current header map. */
    get headers(): Map<string, string>;
    /**
     * Adds a new header to this credentials object.
     * @param singleHeaderName  Header name, it will be ignored if null.
     * @param singleHeaderValue Header value, it will be ignored if null.
     */
    addHeader(singleHeaderName:string, singleHeaderValue:string): void;
}

/**
 * The class used to represent authentication for AWS, like required by data sources like Athena or S3.
 */
export declare class RVAmazonWebServicesCredentials implements IRVDataSourceCredential {
    /**
     * @param key          AWS access key ID.
     * @param secret       AWS secret access key.
     * @param sessionToken Optional temporary session token (for STS / assumed roles).
     */
    constructor(key: string, secret: string, sessionToken?: string);
    /** AWS access key ID. */
    get key(): string;
    /** AWS secret access key. */
    get secret(): string;
    /** Optional temporary session token, or `null` if not set. */
    get sessionToken(): string | null;
}

/**
 * Used to indicate integrated authentication.
 */
export declare class RVIntegratedAuthenticationCredential implements IRVDataSourceCredential {
    constructor();
}

/**
 * Used for Personal Access Token (PAT) authentication.
 */
export declare class RVPersonalAccessTokenDataSourceCredential implements IRVDataSourceCredential {
    /**
     * @param token The personal access token string.
     */
    constructor(token: string);
    /** The personal access token string. */
    get token(): string;
}

/**
 * Used for OAuth Client Credentials authentication.
 */
export declare class RVOAuthDataSourceCredential implements IRVDataSourceCredential {
    /**
     * @param clientId     OAuth client ID.
     * @param clientSecret OAuth client secret.
     */
    constructor(clientId: string, clientSecret: string);
    /** OAuth client ID. */
    get clientId(): string;
    /** OAuth client secret. */
    get clientSecret(): string;
}

/**
 * Used for Microsoft Entra ID authentication.
 */
export declare class RVMicrosoftEntraIDDataSourceCredential implements IRVDataSourceCredential {
    /**
     * @param tenantId     The Azure AD tenant (directory) ID.
     * @param clientId     The application (client) ID registered in Entra ID.
     * @param clientSecret The client secret for the registered application.
     */
    constructor(tenantId: string, clientId: string, clientSecret: string);
    /** The Azure AD tenant (directory) ID. */
    get tenantId(): string;
    /** The application (client) ID registered in Entra ID. */
    get clientId(): string;
    /** The client secret for the registered application. */
    get clientSecret(): string;
}

/**
 * Used for key-pair authentication.
 */
export declare class RVKeyPairDataSourceCredential implements IRVDataSourceCredential {
    /**
     * @param userName   The username associated with the key pair.
     * @param privateKey The private key string (PEM format).
     */
    constructor(userName: string, privateKey: string);
    /** The username associated with the key pair. */
    get userName(): string;
    /** The private key string (PEM format). */
    get privateKey(): string;
}

/**
 * Represents configuration options for connecting to a Redis cache.
 * Values that are not explicitly specified will use the defaults set by StackExchange.Redis.
 */
export declare type RedisCacheOptions = {
    /** Gets or sets the Redis server connection string or endpoint (e.g., "localhost:6379"). */
    connectionString?: string;
    /** Gets or sets the list of endpoint URLs used for connecting to external services or resources. */
    endPoints?: string[];
    /** Gets or sets the username associated with the current session. */
    user?: string;
    /** Gets or sets the password for Redis authentication. */
    password?: string;
    /** Gets or sets a value indicating whether SSL/TLS encryption is enabled. */
    useSsl?: boolean;
    /** Gets or sets the default database number to use. */
    defaultDatabase?: number;
    /** Gets or sets the client name for identification. */
    clientName?: string;
    /** Gets or sets the connection timeout in milliseconds. */
    connectTimeoutMs?: number;
    /** Gets or sets the synchronous operation timeout in milliseconds. */
    syncTimeoutMs?: number;
    /** Gets or sets the asynchronous operation timeout in milliseconds. */
    asyncTimeoutMs?: number;
    /** Gets or sets the number of connection retry attempts. */
    connectRetry?: number;
    /** Gets or sets the keep-alive interval in seconds (-1 to disable). */
    keepAliveSeconds?: number;
    /** Gets or sets a value indicating whether to abort on connection failure. */
    abortOnConnectFail?: boolean;
    /** Gets or sets a value indicating whether admin commands (FLUSHDB, CONFIG, etc.) are allowed. */
    allowAdmin?: boolean;
    /** Gets or sets the reconnection retry policy: "Linear" or "Exponential". */
    reconnectRetryPolicy?: string;
    /** Gets or sets the base delay in milliseconds for the retry policy. */
    retryDelayMs?: number;
}

/**
 * **Beta** — Interface for customizing the data model exposed by a data source.
 *
 * Implement and pass an instance to {@link RevealOptions.dataModelProvider} to:
 * - Edit the schema of a data source by modifying its fields (`editSchema`).
 * - Inject custom calculated fields (`getCalculatedFields`).
 * - Inject custom measures (`getMeasures`).
 *
 * @beta This interface is provided as a beta feature. The API surface may change in future
 * releases without prior notice. It is not yet covered by the standard backward-compatibility guarantees.
 */
export declare interface IRVDataModelProvider {
    /**
     * Called to allow editing the schema fields of the given data source item.
     *
     * New (calculated) fields should not be added here; use {@link getCalculatedFields} instead.
     * To make the edits effective, return a non-null/non-undefined array. When the returned array
     * differs from the original, changes in the original schema are ignored.
     *
     * @param userContext    The user context extracted from the originating request.
     * @param dataSourceItem The data source item whose schema is being requested.
     * @param schema         The base schema containing all known fields.
     * @returns A (possibly modified) array of fields, or `null`/`undefined` to keep the original schema.
     */
    editSchema(userContext: IRVUserContext | null, dataSourceItem: RVDataSourceItem, schema: RVDataModelField[]): Promise<RVDataModelField[] | null | undefined>;

    /**
     * Called to retrieve additional calculated fields for the given data source item.
     *
     * @param userContext    The user context extracted from the originating request.
     * @param dataSourceItem The data source item whose calculated fields are being requested.
     * @returns A list of calculated fields to inject, or `null`/`undefined` if none.
     */
    getCalculatedFields(userContext: IRVUserContext | null, dataSourceItem: RVDataSourceItem): Promise<RVDataModelCalculatedField[] | null | undefined>;

    /**
     * Called to retrieve additional measures for the given data source item.
     *
     * @param userContext    The user context extracted from the originating request.
     * @param dataSourceItem The data source item whose measures are being requested.
     * @returns A list of measures to inject, or `null`/`undefined` if none.
     */
    getMeasures(userContext: IRVUserContext | null, dataSourceItem: RVDataSourceItem): Promise<RVDataModelMeasure[] | null | undefined>;
}

/**
 * Configuration options for headless (server-side) dashboard export.
 */
export declare type RevealExportConfiguration = {
    /**
     * Local path to a ZIP file containing the SDK JS distribution
     * (e.g., `reveal-sdk-distribution-js.zip`).
     */
    sdkJsDistributionFile?: string,
}

/**
 * Class used to configure the Reveal SDK embedded in your application.
 */
export declare type RevealOptions = {
    /**
     * URL path prefix under which the Reveal API is mounted.
     * Must match the path used by the Reveal client-side SDK.
     * @example "/reveal-api"
     */
    basePath?: string,
    /**
     * Directory where the rest of cache files (like downloaded files) will be stored, it defaults to the temporary directory in the system.
     */
    cachePath?: string,
    /**
     * Absolute path to the directory where engine log files are written.
     * When omitted, logs go to stdout/stderr only.
     */
    engineLogDir?: string,
    /**
     * Minimum log level emitted by the engine.
     * Accepted values (case-insensitive): `"Trace"`, `"Debug"`, `"Information"`,
     * `"Warning"`, `"Error"`, `"Critical"`, `"None"`.
     */
    engineLogLevel?: string,
    /** License code to unlock Reveal BI Embedded and get rid of the Trial mode. */
    license?: string,
    /**
     * Root directory used to load data files using the "Local" data source.
     */
    localFileStoragePath?: string,
    /**
     * Called by the engine when it needs credentials for a data source.
     * Return the appropriate {@link IRVDataSourceCredential} subclass, or `null`
     * to fall back to the engine default.
     *
     * @param userContext The user context extracted from the originating request.
     * @param dataSource  The data source that requires credentials.
     * @returns A credential object, or `null` / `undefined` for no override.
     */
    authenticationProvider?: (userContext:IRVUserContext | null, dataSource:RVDashboardDataSource) => Promise<IRVDataSourceCredential | null>,
    /**
     * Called when the engine needs to load a dashboard.
     * Return a readable stream of the `.rdash` file, or `null` to indicate
     * that the dashboard was not found (results in a 404 response).
     *
     * @param userContext  The user context extracted from the originating request.
     * @param dashboardId  The ID of the dashboard to load.
     * @returns A `Readable` stream for the dashboard, or `null` if not found.
     */
    dashboardProvider?: (userContext:IRVUserContext | null, dashboardId:string) => Promise<Readable | null>,
    /**
     * Called when the engine needs to persist a modified dashboard.
     * The `stream` argument contains the updated `.rdash` content.
     *
     * @param userContext  The user context extracted from the originating request.
     * @param dashboardId  The ID of the dashboard being saved.
     * @param stream       Readable stream containing the new dashboard content.
     */
    dashboardStorageProvider?: (userContext:IRVUserContext | null, dashboardId: string, stream: Readable) => Promise<void>,
    /**
     * Called once per incoming HTTP request to extract user-context information
     * (e.g. from session cookies or JWT headers).
     * The returned object is forwarded to all other provider callbacks.
     *
     * @param request The raw Node.js `IncomingMessage`.
     * @returns A user-context object, or `null` for anonymous requests.
     */
    userContextProvider?: (request:IncomingMessage) => IRVUserContext | null,
    /**
     * Called when the engine resolves a data source.
     * Use this to substitute connection strings, change schemas, etc.
     *
     * @param userContext The user context extracted from the originating request.
     * @param dataSource  The data source as configured in the dashboard.
     * @returns The (optionally modified) data source, or `null` for no override.
     */
    dataSourceProvider?: (userContext: IRVUserContext | null, dataSource: RVDashboardDataSource) => Promise<RVDashboardDataSource | null>,
    /**
     * Called when the engine resolves a data source item (e.g. a specific table
     * or file within a data source).
     * Use this to override the item's settings such as the table name.
     *
     * @param userContext The user context extracted from the originating request.
     * @param dataSource  The data source item as configured in the dashboard.
     * @returns The (optionally modified) data source item, or `null` for no override.
     */
    dataSourceItemProvider?: (userContext: IRVUserContext | null, dataSource: RVDataSourceItem) => Promise<RVDataSourceItem | null>,
    /**
     * Called for each item in a data source item list to decide whether it should
     * be visible to the current user.
     * Return `true` to include the item, `false` to hide it.
     *
     * @param userContext    The user context extracted from the originating request.
     * @param dataSourceItem The candidate data source item.
     * @returns `true` to show the item; `false` to hide it.
     */
    dataSourceItemFilter?: (userContext: IRVUserContext | null, dataSourceItem: RVDataSourceItem) => Promise<boolean>,
    /**
     * **Beta** — Called by the engine to allow customizing the data model exposed by a data source.
     * Implement this to edit field schemas, inject calculated fields, or add custom measures.
     *
     * The object must implement the following three methods:
     * - `editSchema(userContext, dataSourceItem, schema)` — edit the existing field list.
     * - `getCalculatedFields(userContext, dataSourceItem)` — return additional calculated fields.
     * - `getMeasures(userContext, dataSourceItem)` — return additional measures.
     *
     * @beta This option is part of the beta {@link IRVDataModelProvider} API and may change in future releases.
     */
    dataModelProvider?: IRVDataModelProvider,
    /**
     * @internal
     * Overrides the resolved path to the Reveal engine binary.
     * Intended for internal testing only — do not use in production.
     */
    _internal_revealEnginePrgPath?: string,
    /**
     * Freeform key/value settings forwarded verbatim to the engine.
     * Contact Infragistics support for recognized keys.
     * @example new Map([["puppeteer_executable_path", "/usr/bin/chromium"]])
     */
    advancedSettings?: Map<string, Object>,
    /**
     * This property controls the maximum number of values displayed in a dashboard filter.
     */
    maxFilterSize?: number,
    /**
     * Sets a limit on the size of a single download (e.g. a CSV file). Default is 200Mb.
     */
    maxDownloadSize?: number,
    /**
     * Set this property to the expected maximum size of pivot tables or grids, given as a number of cells.
     * The engine avoids using too much memory and this setting provides a hint for its memory management.
     * Default is 10 million cells.
     */
    maxInMemoryCells?: number,
    /**
     * Set this property to the expected maximum size of cells to be processed from any data source
     * (e.g. from a Sql Server table rows, from CSV rows, etc.).
     * The engine avoids using too much disk space for its cache and this setting provides a hint for its
     * caching management. Default is 10 million cells.
     */
    maxStorageCells?: number,
    /**
     * Set this property to the expected maximum size of pivot tables or grids,
     * given as the total number of characters in all of its cells.
     * The engine avoids using too much memory and this setting provides a hint for its memory
     * management. Default is 64 million.
     */
    maxTotalStringsSize?: number,
    /**
     * Sets a limit on the number of characters any string in a dataset column may have.
     * Default is 256.
     */
    maxStringCellSize?: number,
    /**
     * Names of `@revealbi/data-*` packages to load as data-source connectors.
     * Each string should be the connector suffix (e.g. `"mssql"` loads
     * `@revealbi/data-mssql`).
     * @example ["mssql", "mysql", "postgres"]
     */
    dataSources?: Array<string>,
    /**
     * Uses the legacy SQLite cache.
     * It defaults to true.
     */
    isLegacyCacheEnabled?: boolean,
    /**
     * Enables the use of encryption of the SQLite cache (only works for M.D.SQLite).
     * It defaults to false.
     */
    enableCacheEncryption?: boolean,
    /**
     * Sets the encryption password for the SQLite cache files (ignored if encryption is disabled).
     */
    cacheEncryptionPassword?: string,
    /**
     * Enables the next-generation local data-processing engine.
     * Defaults to `false`. Enable only when advised by Infragistics support.
     */
    newLocalProcessingEnabled?: boolean,
    /**
     * Redis connection options for distributed caching across multiple server instances.
     * When provided, the engine uses Redis instead of the local-disk cache
     * (set {@link isLegacyCacheEnabled} to `false`).
     */
    redisOptions?: RedisCacheOptions,
    /**
     * Configuration for headless (server-side) dashboard export via Chromium/Playwright.
     */
    exportConfiguration?: RevealExportConfiguration,
    /**
     * Plugin callback handlers, keyed by plugin name.
     * Each entry declares the callbacks that a specific plugin exposes.
     * When the engine invokes `/plugin/{pluginName}/{callbackName}`, the
     * matching handler is called with the current user context and the raw
     * request body string.
     *
     * @example
     * ```ts
     * plugins: [
     *   {
     *     name: "HelloWorld",
     *     callbacks: {
     *       process: async (userContext, message) => `Hello, ${message}!`,
     *     },
     *   },
     * ]
     * ```
     */
    plugins?: any[],
    /**
     * Called by the engine for system-initiated requests (i.e. requests that
     * originate inside the engine rather than from an end-user HTTP request).
     * Return the {@link IRVUserContext} that should be used for these requests,
     * or `null` to treat them as anonymous.
     *
     * When not provided, {@link userContextProvider} is called with `null` as
     * the request argument as a fallback.
     *
     * @returns A user-context object, or `null` for anonymous system requests.
     */
    systemUserContextProvider?: () => IRVUserContext | null,
}

/**
 * Handle to a running Reveal server instance, returned as part of
 * {@link RevealRequestListener}.
 */
export declare class RevealServer {
    /**
     * Gracefully stops the server and releases all resources (engine process,
     * callback HTTP server, browser instance).
     * @param callback Optional function invoked after the server has fully stopped.
     */
    close(callback?: () => void): void;
    /** Dashboard export utilities — render dashboards to PDF, images, or Excel. */
    exporter: IDashboardExporter;
}

/**
 * The value returned by the default {@link create} export.
 * It is both a standard Node.js `RequestListener` (suitable for `http.createServer`)
 * and a {@link RevealServer} handle with a `.close()` method and `.exporter`.
 *
 * @example
 * ```ts
 * import express from "express";
 * import reveal from "@revealbi/node-sdk";
 *
 * const app = express();
 * const revealMiddleware = reveal({ license: "YOUR_LICENSE_KEY" });
 * app.use("/reveal-api/", revealMiddleware);
 * ```
 */
export declare type RevealRequestListener = RequestListener & RevealServer;

/**
 * Creates and starts the Reveal embedded analytics server.
 *
 * The returned {@link RevealRequestListener} can be passed directly to
 * `http.createServer()` or mounted as Express / Koa middleware.
 * Call `.close()` on the returned value to shut the server down cleanly.
 *
 * @param options Configuration options — see {@link RevealOptions}.
 * @returns A combined request-listener / server-handle object.
 *
 * @example
 * ```ts
 * import reveal from "@revealbi/node-sdk";
 * const server = reveal({ license: "YOUR_LICENSE_KEY", cachePath: "/var/cache/reveal" });
 * require("http").createServer(server).listen(5111);
 * ```
 */
export default function create(options?: RevealOptions): RevealRequestListener;
