import { OperationKeys, PrimaryKeyType } from "@decaf-ts/db-decorators";
import { CouchDBAdapter, MangoQuery, ViewResponse } from "@decaf-ts/for-couchdb";
import { DocumentScope, ServerScope } from "nano";
import { Model } from "@decaf-ts/decorator-validation";
import { NanoConfig, NanoFlags } from "./types.d.mts";
import { Adapter, Context, ContextOf, ContextualArgs, MaybeContextualArg, RelationsMetadata, Repository } from "@decaf-ts/core";
import { NanoRepository } from "./NanoRepository.d.mts";
import { NanoDispatch } from "./NanoDispatch.d.mts";
import { Constructor } from "@decaf-ts/decoration";
/**
 * @description Sets the creator or updater field in a model based on the user in the context
 * @summary Callback function used in decorators to automatically set the created_by or updated_by fields
 * with the username from the context when a document is created or updated
 * @template M - Type extending Model
 * @template R - Type extending NanoRepository<M>
 * @template V - Type extending RelationsMetadata
 * @param {R} this - The repository instance
 * @param {Context<NanoFlags>} context - The operation context containing user information
 * @param {V} data - The relation metadata
 * @param key - The property key to set with the username
 * @param {M} model - The model instance being created or updated
 * @return {Promise<void>} A promise that resolves when the operation is complete
 * @function createdByOnNanoCreateUpdate
 * @memberOf module:for-nano
 * @mermaid
 * sequenceDiagram
 *   participant F as createdByOnNanoCreateUpdate
 *   participant C as Context
 *   participant M as Model
 *   F->>C: get("user")
 *   C-->>F: user object
 *   F->>M: set key to user.name
 *   Note over F: If no user in context
 *   F-->>F: throw UnsupportedError
 */
export declare function createdByOnNanoCreateUpdate<M extends Model, R extends NanoRepository<M>, V extends RelationsMetadata>(this: R, context: ContextOf<R>, data: V, key: keyof M, model: M): Promise<void>;
/**
 * @description Adapter for interacting with Nano databases
 * @summary Provides a standardized interface for performing CRUD operations on Nano databases,
 * extending the CouchDB adapter with Nano-specific functionality. This adapter handles document
 * creation, reading, updating, and deletion, as well as bulk operations and index management.
 * @template DocumentScope - The Nano document scope type
 * @template NanoFlags - Configuration flags for Nano operations
 * @template Context - Context type for operations
 * @param {DocumentScope<any>} scope - The Nano document scope to use for database operations
 * @param {string} [alias] - Optional alias for the adapter
 * @class NanoAdapter
 * @example
 * ```typescript
 * // Connect to a Nano database
 * const server = NanoAdapter.connect('admin', 'password', 'localhost:5984');
 * const db = server.db.use('my_database');
 *
 * // Create an adapter instance
 * const adapter = new NanoAdapter(db);
 *
 * // Use the adapter for database operations
 * const document = await adapter.read('users', '123');
 * ```
 * @mermaid
 * classDiagram
 *   class CouchDBAdapter {
 *     +flags()
 *     +Dispatch()
 *     +index()
 *     +create()
 *     +read()
 *     +update()
 *     +delete()
 *   }
 *   class NanoAdapter {
 *     +flags()
 *     +Dispatch()
 *     +index()
 *     +create()
 *     +createAll()
 *     +read()
 *     +readAll()
 *     +update()
 *     +updateAll()
 *     +delete()
 *     +deleteAll()
 *     +raw()
 *     +static connect()
 *     +static createDatabase()
 *     +static deleteDatabase()
 *     +static createUser()
 *     +static deleteUser()
 *     +static decoration()
 *   }
 *   CouchDBAdapter <|-- NanoAdapter
 */
export declare class NanoAdapter extends CouchDBAdapter<NanoConfig, DocumentScope<any>, Context<NanoFlags>> {
    constructor(scope: NanoConfig, alias?: string);
    /**
     * @description Shuts down the adapter instance
     * @summary Cleans up internal resources and clears the cached Nano client instance
     * @return {Promise<void>} A promise that resolves when shutdown completes
     */
    shutdown(...args: MaybeContextualArg<Context<NanoFlags>>): Promise<void>;
    /**
     * @description Lazily creates and returns the Nano DocumentScope client
     * @summary Uses the adapter configuration to establish a connection and wrap a database scope with credentials
     * @return {DocumentScope<any>} The ready-to-use Nano DocumentScope for the configured database
     */
    protected getClient(): any;
    /**
     * @description Generates flags for database operations
     * @summary Creates a set of flags for a specific operation, including user information
     * @template M - Type extending Model
     * @param {OperationKeys} operation - The operation being performed (create, read, update, delete)
     * @param {Constructor<M>} model - The model constructor
     * @param {Partial<NanoFlags>} flags - Partial flags to be merged
     * @return {Promise<NanoFlags>} Complete flags for the operation
     */
    protected flags<M extends Model>(operation: OperationKeys, model: Constructor<M>, flags: Partial<NanoFlags>, ...args: any[]): Promise<NanoFlags>;
    /**
     * @description Creates a new NanoDispatch instance
     * @summary Returns a dispatcher for handling Nano-specific operations
     * @return {NanoDispatch} A new NanoDispatch instance
     */
    protected Dispatch(): NanoDispatch;
    repository<R extends Repository<any, Adapter<NanoConfig, DocumentScope<any>, MangoQuery, Context<NanoFlags>>>>(): Constructor<R>;
    /**
     * @description Creates database indexes for models
     * @summary Generates and creates indexes in the Nano database based on the provided models
     * @template M - Type extending Model
     * @param models - Model constructors to create indexes for
     * @return {Promise<void>} A promise that resolves when all indexes are created
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant G as generateIndexes
     *   participant DB as Nano Database
     *   A->>G: generateIndexes(models)
     *   G-->>A: indexes
     *   loop For each index
     *     A->>DB: createIndex(index)
     *     DB-->>A: response
     *     Note over A: Check if index already exists
     *     alt Index exists
     *       A-->>A: throw ConflictError
     *     end
     *   end
     */
    protected index<M extends Model>(...models: Constructor<M>[]): Promise<void>;
    /**
     * @description Creates a new document in the database
     * @summary Inserts a new document into the Nano database with the provided data
     * @param {string} tableName - The name of the table/collection
     * @param {string | number} id - The document identifier
     * @param {Record<string, any>} model - The document data to insert
     * @return {Promise<Record<string, any>>} A promise that resolves to the created document with metadata
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Database
     *   A->>DB: insert(model)
     *   alt Success
     *     DB-->>A: response with ok=true
     *     A->>A: assignMetadata(model, response.rev)
     *     A-->>A: return document with metadata
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   else Not OK
     *     DB-->>A: response with ok=false
     *     A-->>A: throw InternalError
     *   end
     */
    create<M extends Model>(tableName: Constructor<M>, id: PrimaryKeyType, model: Record<string, any>, ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>>;
    /**
     * @description Creates multiple documents in the database
     * @summary Inserts multiple documents into the Nano database in a single bulk operation
     * @param {string} tableName - The name of the table/collection
     * @param {string[] | number[]} ids - Array of document identifiers
     * @param models - Array of document data to insert
     * @return A promise that resolves to an array of created documents with metadata
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Database
     *   A->>DB: bulk({docs: models})
     *   alt Success
     *     DB-->>A: response array
     *     A->>A: Check if all responses have no errors
     *     alt All OK
     *       A->>A: assignMultipleMetadata(models, revs)
     *       A-->>A: return documents with metadata
     *     else Some errors
     *       A->>A: Collect error messages
     *       A-->>A: throw InternalError with collected messages
     *     end
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   end
     */
    createAll<M extends Model>(tableName: Constructor<M>, ids: PrimaryKeyType[], models: Record<string, any>[], ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>[]>;
    /**
     * @description Retrieves a document from the database
     * @summary Fetches a single document from the Nano database by its ID
     * @param {string} tableName - The name of the table/collection
     * @param {string | number} id - The document identifier
     * @return {Promise<Record<string, any>>} A promise that resolves to the retrieved document with metadata
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Database
     *   A->>A: generateId(tableName, id)
     *   A->>DB: get(_id)
     *   alt Success
     *     DB-->>A: record
     *     A->>A: assignMetadata(record, record._rev)
     *     A-->>A: return document with metadata
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   end
     */
    read<M extends Model>(tableName: Constructor<M>, id: PrimaryKeyType, ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>>;
    /**
     * @description Retrieves multiple documents from the database
     * @summary Fetches multiple documents from the Nano database by their IDs in a single operation
     * @param {string} tableName - The name of the table/collection
     * @param {Array<string | number | bigint>} ids - Array of document identifiers
     * @return A promise that resolves to an array of retrieved documents with metadata
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Database
     *   A->>A: Map ids to generateId(tableName, id)
     *   A->>DB: fetch({keys: mappedIds}, {})
     *   DB-->>A: results
     *   A->>A: Process each result row
     *   loop For each row
     *     alt Row has error
     *       A-->>A: throw InternalError
     *     else Row has document
     *       A->>A: assignMetadata(doc, doc._rev)
     *     else No document
     *       A-->>A: throw InternalError
     *     end
     *   end
     *   A-->>A: return documents with metadata
     */
    readAll<M extends Model>(tableName: Constructor<M>, ids: (string | number | bigint)[], ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>[]>;
    /**
     * @description Updates a document in the database
     * @summary Updates an existing document in the Nano database with the provided data
     * @param {string} tableName - The name of the table/collection
     * @param {string | number} id - The document identifier
     * @param {Record<string, any>} model - The updated document data
     * @return {Promise<Record<string, any>>} A promise that resolves to the updated document with metadata
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Database
     *   A->>DB: insert(model)
     *   alt Success
     *     DB-->>A: response with ok=true
     *     A->>A: assignMetadata(model, response.rev)
     *     A-->>A: return document with metadata
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   else Not OK
     *     DB-->>A: response with ok=false
     *     A-->>A: throw InternalError
     *   end
     */
    update<M extends Model>(tableName: Constructor<M>, id: PrimaryKeyType, model: Record<string, any>, ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>>;
    /**
     * @description Updates multiple documents in the database
     * @summary Performs a bulk update operation on the Nano database for the provided documents
     * @param {string} tableName - The name of the table/collection
     * @param {Array<string|number>} ids - Array of document identifiers
     * @param {Promise<Array<Record<string, any>>>} models - Array of updated document data
     * @return {Promise<Promise<Array<Record<string, any>>>>} A promise that resolves to the updated documents with metadata
     */
    updateAll<M extends Model>(tableName: Constructor<M>, ids: PrimaryKeyType[], models: Record<string, any>[], ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>[]>;
    /**
     * @description Deletes a document from the database
     * @summary Removes a single document from the Nano database by its ID and returns the deleted document metadata
     * @param {string} tableName - The name of the table/collection
     * @param {string|number} id - The document identifier
     * @return {Promise<Record<string, any>>} A promise that resolves to the deleted document with metadata
     */
    delete<M extends Model>(tableName: Constructor<M>, id: PrimaryKeyType, ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>>;
    /**
     * @description Deletes multiple documents from the database
     * @summary Performs a bulk delete operation for the provided IDs and returns the deleted documents metadata
     * @param {string} tableName - The name of the table/collection
     * @param {Array<string|number|bigint>} ids - Array of document identifiers to delete
     * @return {Promise<Array<Record<string, any>>>} A promise resolving to the deleted documents with metadata
     */
    deleteAll<M extends Model>(tableName: Constructor<M>, ids: PrimaryKeyType[], ...args: ContextualArgs<Context<NanoFlags>>): Promise<Record<string, any>[]>;
    /**
     * @description Executes a raw Mango query against the database
     * @summary Runs a Mango query using Nano's find API and optionally returns only the documents array
     * @template R - The expected response or document array type
     * @param {MangoQuery} rawInput - The Mango query to execute
     * @param {boolean} [docsOnly=true] - Whether to return only the docs array or the full response
     * @return {Promise<R>} A promise that resolves to the query result, shaped according to docsOnly
     */
    raw<R>(rawInput: MangoQuery, docsOnly?: boolean, ...args: ContextualArgs<Context<NanoFlags>>): Promise<R>;
    view<R>(ddoc: string, viewName: string, options: Record<string, any>, ..._args: ContextualArgs<Context<NanoFlags>>): Promise<ViewResponse<R>>;
    /**
     * @description Establishes a connection to a Nano (CouchDB) server
     * @summary Creates and returns a Nano ServerScope using the given credentials, host, and protocol
     * @param {string} user - Username used for authentication
     * @param {string} pass - Password used for authentication
     * @param {string} [host="localhost:5984"] - Host and port of the CouchDB server
     * @param {("http"|"https")} [protocol="http"] - Protocol to use for the connection
     * @return {ServerScope} The Nano ServerScope connection
     */
    static connect(user: string, pass: string, host?: string, protocol?: "http" | "https", agent?: any): ServerScope;
    /**
     * @description Creates a new database on the Nano server
     * @summary Creates a new database with the specified name on the connected Nano server
     * @param {ServerScope} con - The Nano server connection
     * @param {string} name - The name of the database to create
     * @return {Promise<void>} A promise that resolves when the database is created
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Server
     *   A->>DB: db.create(name)
     *   alt Success
     *     DB-->>A: result with ok=true
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   else Not OK
     *     DB-->>A: result with ok=false
     *     A-->>A: throw parseError(error, reason)
     *   end
     */
    static createDatabase(con: ServerScope, name: string): Promise<void>;
    /**
     * @description Deletes a database from the Nano server
     * @summary Removes an existing database with the specified name from the connected Nano server
     * @param {ServerScope} con - The Nano server connection
     * @param {string} name - The name of the database to delete
     * @return {Promise<void>} A promise that resolves when the database is deleted
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant DB as Nano Server
     *   A->>DB: db.destroy(name)
     *   alt Success
     *     DB-->>A: result with ok=true
     *   else Error
     *     DB-->>A: error
     *     A-->>A: throw parseError(e)
     *   else Not OK
     *     DB-->>A: result with ok=false
     *     A-->>A: throw InternalError
     *   end
     */
    static deleteDatabase(con: ServerScope, name: string): Promise<void>;
    /**
     * @description Closes the keep-alive agent associated with a Nano connection
     * @summary Destroys the custom HTTP/HTTPS agent that was created during connection setup
     * @param {ServerScope} con - The Nano server connection whose agent should be destroyed
     */
    static closeConnection(con?: ServerScope | null): void;
    /**
     * @description Creates a new user and grants access to a database
     * @summary Creates a new user in the Nano server and configures security to grant the user access to a specific database
     * @param {ServerScope} con - The Nano server connection
     * @param {string} dbName - The name of the database to grant access to
     * @param {string} user - The username to create
     * @param {string} pass - The password for the new user
     * @param {string[]} [roles=["reader", "writer"]] - The roles to assign to the user
     * @return {Promise<void>} A promise that resolves when the user is created and granted access
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant U as _users Database
     *   participant S as Security API
     *   A->>A: Create user object
     *   A->>U: insert(user)
     *   alt Success
     *     U-->>A: response with ok=true
     *     A->>S: PUT _security with user permissions
     *     alt Security Success
     *       S-->>A: security response with ok=true
     *     else Security Failure
     *       S-->>A: security response with ok=false
     *       A-->>A: throw InternalError
     *     end
     *   else Error
     *     U-->>A: error
     *     A-->>A: throw parseError(e)
     *   else Not OK
     *     U-->>A: response with ok=false
     *     A-->>A: throw InternalError
     *   end
     */
    static createUser(con: ServerScope, dbName: string, user: string, pass: string, roles?: string[]): Promise<void>;
    /**
     * @description Deletes a user from the Nano server
     * @summary Removes an existing user from the Nano server
     * @param {ServerScope} con - The Nano server connection
     * @param {string} dbName - The name of the database (used for logging purposes)
     * @param {string} user - The username to delete
     * @return {Promise<void>} A promise that resolves when the user is deleted
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant U as _users Database
     *   A->>A: Generate user ID
     *   A->>U: get(id)
     *   U-->>A: user document
     *   A->>U: destroy(id, user._rev)
     *   alt Success
     *     U-->>A: success response
     *   else Error
     *     U-->>A: error
     *     A-->>A: throw parseError(e)
     *   end
     */
    static deleteUser(con: ServerScope, dbName: string, user: string): Promise<void>;
    /**
     * @description Sets up decorations for Nano-specific model properties
     * @summary Configures decorators for created_by and updated_by fields in models to be automatically
     * populated with the user from the context when documents are created or updated
     * @return {void}
     * @mermaid
     * sequenceDiagram
     *   participant A as NanoAdapter
     *   participant D as Decoration
     *   participant R as Repository
     *   A->>R: key(PersistenceKeys.CREATED_BY)
     *   R-->>A: createdByKey
     *   A->>D: flavouredAs("nano")
     *   A->>D: for(createdByKey)
     *   A->>D: define(onCreate(createdByOnNanoCreateUpdate), propMetadata)
     *   A->>D: apply()
     *   A->>R: key(PersistenceKeys.UPDATED_BY)
     *   R-->>A: updatedByKey
     *   A->>D: flavouredAs("nano")
     *   A->>D: for(updatedByKey)
     *   A->>D: define(onCreate(createdByOnNanoCreateUpdate), propMetadata)
     *   A->>D: apply()
     */
    static decoration(): void;
}
