import { Adapter, Sequence, type SequenceOptions } from "@decaf-ts/core";
import { BaseError, Context, RepositoryFlags } from "@decaf-ts/db-decorators";
import "reflect-metadata";
import { Constructor, Model } from "@decaf-ts/decorator-validation";
import { MangoQuery } from "./types";
import { CouchDBStatement } from "./query";
/**
 * @description Abstract adapter for CouchDB database operations
 * @summary Provides a base implementation for CouchDB database operations, including CRUD operations, sequence management, and error handling
 * @template Y - The scope type
 * @template F - The repository flags type
 * @template C - The context type
 * @param {Y} scope - The scope for the adapter
 * @param {string} flavour - The flavour of the adapter
 * @param {string} [alias] - Optional alias for the adapter
 * @class
 * @example
 * // Example of extending CouchDBAdapter
 * class MyCouchDBAdapter extends CouchDBAdapter<MyScope, MyFlags, MyContext> {
 *   constructor(scope: MyScope) {
 *     super(scope, 'my-couchdb', 'my-alias');
 *   }
 *
 *   // Implement abstract methods
 *   async index<M extends Model>(...models: Constructor<M>[]): Promise<void> {
 *     // Implementation
 *   }
 *
 *   async raw<R>(rawInput: MangoQuery, docsOnly: boolean): Promise<R> {
 *     // Implementation
 *   }
 *
 *   async create(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>> {
 *     // Implementation
 *   }
 *
 *   async read(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>> {
 *     // Implementation
 *   }
 *
 *   async update(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>> {
 *     // Implementation
 *   }
 *
 *   async delete(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>> {
 *     // Implementation
 *   }
 * }
 */
export declare abstract class CouchDBAdapter<Y, F extends RepositoryFlags, C extends Context<F>> extends Adapter<Y, MangoQuery, F, C> {
    protected constructor(scope: Y, flavour: string, alias?: string);
    /**
     * @description Creates a new CouchDB statement for querying
     * @summary Factory method that creates a new CouchDBStatement instance for building queries
     * @template M - The model type
     * @return {CouchDBStatement<M, any>} A new CouchDBStatement instance
     */
    Statement<M extends Model>(): CouchDBStatement<M, any>;
    /**
     * @description Creates a new CouchDB sequence
     * @summary Factory method that creates a new CouchDBSequence instance for managing sequences
     * @param {SequenceOptions} options - The options for the sequence
     * @return {Promise<Sequence>} A promise that resolves to a new Sequence instance
     */
    Sequence(options: SequenceOptions): Promise<Sequence>;
    /**
     * @description Initializes the adapter by creating indexes for all managed models
     * @summary Sets up the necessary database indexes for all models managed by this adapter
     * @return {Promise<void>} A promise that resolves when initialization is complete
     */
    initialize(): Promise<void>;
    /**
     * @description Creates indexes for the given models
     * @summary Abstract method that must be implemented to create database indexes for the specified models
     * @template M - The model type
     * @param {...Constructor<M>} models - The model constructors to create indexes for
     * @return {Promise<void>} A promise that resolves when all indexes are created
     */
    protected abstract index<M extends Model>(...models: Constructor<M>[]): Promise<void>;
    /**
     * @description Executes a raw Mango query against the database
     * @summary Abstract method that must be implemented to execute raw Mango queries
     * @template R - The result type
     * @param {MangoQuery} rawInput - The raw Mango query to execute
     * @param {boolean} docsOnly - Whether to return only the documents or the full response
     * @return {Promise<R>} A promise that resolves to the query result
     */
    abstract raw<R>(rawInput: MangoQuery, docsOnly: boolean): Promise<R>;
    /**
     * @description Assigns metadata to a model
     * @summary Adds revision metadata to a model as a non-enumerable property
     * @param {Record<string, any>} model - The model to assign metadata to
     * @param {string} rev - The revision string to assign
     * @return {Record<string, any>} The model with metadata assigned
     */
    protected assignMetadata(model: Record<string, any>, rev: string): Record<string, any>;
    /**
     * @description Assigns metadata to multiple models
     * @summary Adds revision metadata to multiple models as non-enumerable properties
     * @param models - The models to assign metadata to
     * @param {string[]} revs - The revision strings to assign
     * @return The models with metadata assigned
     */
    protected assignMultipleMetadata(models: Record<string, any>[], revs: string[]): Record<string, any>[];
    /**
     * @description Prepares a record for creation
     * @summary Adds necessary CouchDB fields to a record before creation
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param {Record<string, any>} model - The model to prepare
     * @return A tuple containing the tableName, id, and prepared record
     */
    protected createPrefix(tableName: string, id: string | number, model: Record<string, any>): (string | number | Record<string, any>)[];
    /**
     * @description Creates a new record in the database
     * @summary Abstract method that must be implemented to create a new record
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param {Record<string, any>} model - The model to create
     * @param {...any[]} args - Additional arguments
     * @return {Promise<Record<string, any>>} A promise that resolves to the created record
     */
    abstract create(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>>;
    /**
     * @description Prepares multiple records for creation
     * @summary Adds necessary CouchDB fields to multiple records before creation
     * @param {string} tableName - The name of the table
     * @param {string[]|number[]} ids - The IDs of the records
     * @param models - The models to prepare
     * @return A tuple containing the tableName, ids, and prepared records
     * @throws {InternalError} If ids and models arrays have different lengths
     */
    protected createAllPrefix(tableName: string, ids: string[] | number[], models: Record<string, any>[]): (string | string[] | number[] | Record<string, any>[])[];
    /**
     * @description Reads a record from the database
     * @summary Abstract method that must be implemented to read a record
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param {...any[]} args - Additional arguments
     * @return {Promise<Record<string, any>>} A promise that resolves to the read record
     */
    abstract read(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>>;
    /**
     * @description Prepares a record for update
     * @summary Adds necessary CouchDB fields to a record before update
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param model - The model to prepare
     * @return A tuple containing the tableName, id, and prepared record
     * @throws {InternalError} If no revision number is found in the model
     */
    updatePrefix(tableName: string, id: string | number, model: Record<string, any>): (string | number | Record<string, any>)[];
    /**
     * @description Updates a record in the database
     * @summary Abstract method that must be implemented to update a record
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param {Record<string, any>} model - The model to update
     * @param {any[]} args - Additional arguments
     * @return A promise that resolves to the updated record
     */
    abstract update(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>>;
    /**
     * @description Prepares multiple records for update
     * @summary Adds necessary CouchDB fields to multiple records before update
     * @param {string} tableName - The name of the table
     * @param {string[]|number[]} ids - The IDs of the records
     * @param models - The models to prepare
     * @return A tuple containing the tableName, ids, and prepared records
     * @throws {InternalError} If ids and models arrays have different lengths or if no revision number is found in a model
     */
    protected updateAllPrefix(tableName: string, ids: string[] | number[], models: Record<string, any>[]): (string | string[] | number[] | Record<string, any>[])[];
    /**
     * @description Deletes a record from the database
     * @summary Abstract method that must be implemented to delete a record
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @param {any[]} args - Additional arguments
     * @return A promise that resolves to the deleted record
     */
    abstract delete(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>>;
    /**
     * @description Generates a CouchDB document ID
     * @summary Combines the table name and ID to create a CouchDB document ID
     * @param {string} tableName - The name of the table
     * @param {string|number} id - The ID of the record
     * @return {string} The generated CouchDB document ID
     */
    protected generateId(tableName: string, id: string | number): string;
    /**
     * @description Parses an error and converts it to a BaseError
     * @summary Converts various error types to appropriate BaseError subtypes
     * @param {Error|string} err - The error to parse
     * @param {string} [reason] - Optional reason for the error
     * @return {BaseError} The parsed error as a BaseError
     */
    parseError(err: Error | string, reason?: string): BaseError;
    /**
     * @description Checks if an attribute is reserved
     * @summary Determines if an attribute name is reserved in CouchDB
     * @param {string} attr - The attribute name to check
     * @return {boolean} True if the attribute is reserved, false otherwise
     */
    protected isReserved(attr: string): boolean;
    /**
     * @description Static method to parse an error and convert it to a BaseError
     * @summary Converts various error types to appropriate BaseError subtypes based on error codes and messages
     * @param {Error|string} err - The error to parse
     * @param {string} [reason] - Optional reason for the error
     * @return {BaseError} The parsed error as a BaseError
     * @mermaid
     * sequenceDiagram
     *   participant Caller
     *   participant parseError
     *   participant ErrorTypes
     *
     *   Caller->>parseError: err, reason
     *   Note over parseError: Check if err is already a BaseError
     *   alt err is BaseError
     *     parseError-->>Caller: return err
     *   else err is string
     *     Note over parseError: Extract code from string
     *     alt code matches "already exist|update conflict"
     *       parseError->>ErrorTypes: new ConflictError(code)
     *       ErrorTypes-->>Caller: ConflictError
     *     else code matches "missing|deleted"
     *       parseError->>ErrorTypes: new NotFoundError(code)
     *       ErrorTypes-->>Caller: NotFoundError
     *     end
     *   else err has code property
     *     Note over parseError: Extract code and reason
     *   else err has statusCode property
     *     Note over parseError: Extract code and reason
     *   else
     *     Note over parseError: Use err.message as code
     *   end
     *
     *   Note over parseError: Switch on code
     *   alt code is 401, 412, or 409
     *     parseError->>ErrorTypes: new ConflictError(reason)
     *     ErrorTypes-->>Caller: ConflictError
     *   else code is 404
     *     parseError->>ErrorTypes: new NotFoundError(reason)
     *     ErrorTypes-->>Caller: NotFoundError
     *   else code is 400
     *     alt code matches "No index exists"
     *       parseError->>ErrorTypes: new IndexError(err)
     *       ErrorTypes-->>Caller: IndexError
     *     else
     *       parseError->>ErrorTypes: new InternalError(err)
     *       ErrorTypes-->>Caller: InternalError
     *     end
     *   else code matches "ECONNREFUSED"
     *     parseError->>ErrorTypes: new ConnectionError(err)
     *     ErrorTypes-->>Caller: ConnectionError
     *   else
     *     parseError->>ErrorTypes: new InternalError(err)
     *     ErrorTypes-->>Caller: InternalError
     *   end
     */
    protected static parseError(err: Error | string, reason?: string): BaseError;
}
