import { Pool, PoolConnection } from 'mysql2/promise';
import * as axios_rate_limit from 'axios-rate-limit';
import { AxiosInstance } from 'axios';
import { Debugger } from 'debug';

declare abstract class BaseConnection {
}

declare class MysqlTypeConnection extends BaseConnection {
    pool: Pool;
    protected transactionActive: boolean;
    protected transactionConnection: PoolConnection | null;
    constructor(host: string, port: number, user: string, password: string, database: string, connectionLimit?: number, queueLimit?: number);
    logQuery(queryString: string, queryData: any): void;
    formatQuery(queryString: string, queryData: any): string;
    exec(queryString: string, queryData: any, options: {
        [key: string]: any;
    }): Promise<any>;
    beginTransaction(): Promise<void>;
    commitTransaction(): Promise<void>;
    rollbackTransaction(): Promise<void>;
}

declare class RestTypeConnection extends BaseConnection {
    static DEFAULT_MAX_REQUEST_LIMIT: number;
    static DEFAULT_PER_MILISECOND_LIMIT: number;
    static DEFAULT_TIMEOUT: number;
    axiosConnection: AxiosInstance;
    constructor(baseUrl: string, baseHeaders: any, { additionalHeaders, maxRequestsLimit, perMillisecondsLimit, timeout, httpsAgent }?: {
        additionalHeaders?: {} | undefined;
        maxRequestsLimit?: number | undefined;
        perMillisecondsLimit?: number | undefined;
        timeout?: number | undefined;
        httpsAgent?: null | undefined;
    });
    createAxiosConnection(baseUrl: string, baseHeaders: any, additionalHeaders: any, maxRequestsLimit: number, perMillisecondsLimit: number, timeout: number, httpsAgent: any): axios_rate_limit.RateLimitedAxiosInstance;
    exec(method: string, url: string, { params, body, fullResponse, headers }?: {
        params?: null | undefined;
        body?: null | undefined;
        fullResponse?: boolean | undefined;
        headers?: {} | undefined;
    }): Promise<any>;
}

declare abstract class BaseModel {
    constructor(model?: any);
    abstract populate(model: any): void;
}

declare abstract class BaseMysqlModel extends BaseModel {
    abstract hasChanged(newModel: BaseMysqlModel): boolean;
    abstract toDataBase(): any;
}

declare abstract class BaseRestModel extends BaseModel {
}

declare class FileLogger {
    static DEFAULT_RELATIVE_FILE_LOCATION: string;
    static PREFIX_SEPARATOR: string;
    static INFO_PREFIX: string;
    static ERROR_PREFIX: string;
    prefix: string;
    fileName: string;
    fileLocation: string;
    normalDebug: boolean;
    debug: Debugger;
    infoDebug: Debugger;
    errorDebug: Debugger;
    completeFileLocation: string;
    completeFilePath: string;
    constructor(fileName: string, prefix: string, normalDebug: boolean, fileLocation: string);
    createLocation(path: string): void;
    log(...content: string[]): void;
    info(content: string, appendPrefix?: boolean): void;
    error(content: string | null, error: any, appendPrefix?: boolean): void;
    extend(prefix: string): FileLogger;
}

/**
 * Creates a logger with today's date as filename
 */
declare class DailyLogger extends FileLogger {
    constructor(prefix: string, normalDebug: boolean, fileLocation: string);
}
/**
 * Function that returns a logger to specified folder, and filename equal to today's date in yyyy-mm-dd format
 * @param {string} prefix prefix for all logs to start with
 * @param {boolean} normalDebug wether to write logs using normal debug module as well as file
 * @param {string} fileLocation log file location insied ./log
 * @returns {DailyLogger}
 */
declare const dailyLogger: (prefix: string, normalDebug?: boolean, fileLocation?: string) => DailyLogger;

/**
 * Creates a logger with each run of a process, with timestamp as filename
 */
declare class RunLogger extends FileLogger {
    constructor(prefix: string, normalDebug: boolean, fileLocation: string);
}
/**
 * Function that returns a logger to specified folder, and filename equal to current timestamp format
 * @param {string} prefix prefix for all logs to start with
 * @param {boolean} normalDebug wether to write logs using normal debug module as well as file
 * @param {string} fileLocation log file location insied ./log
 * @returns {RunLogger}
 */
declare const runLogger: (prefix: string, normalDebug?: boolean, fileLocation?: string) => RunLogger;

declare class CustomLogger extends FileLogger {
}
/**
 * Function that returns a logger to specified folder, and a given filename
 * @param {string} fileName fileName to log into
 * @param {string} prefix prefix for all logs to start with
 * @param {boolean} normalDebug wether to write logs using normal debug module as well as file
 * @param {string} fileLocation log file location inside ./log
 * @returns
 */
declare const customLogger: (fileName: string, prefix: string, normalDebug?: boolean, fileLocation?: string) => CustomLogger;

type TApiLogger = FileLogger | Debugger | Console;
type TApiLoggerOpt = FileLogger | Debugger | Console | null;
type TComplexCondition = {
    [key: string]: TSimpleCondition;
};
type TSimpleCondition = string | number | boolean | Date | string[] | number[];
type TMultipelCondition = (TComplexCondition | TSimpleCondition)[];
type TFollowOptions = string[] | "*";
declare enum EQueryOperators {
    eq = "=",
    neq = "<>",
    like = "LIKE",
    notlike = "NOT LIKE",
    in = "IN",
    notin = "NOT IN",
    notnull = "IS NOT NULL",
    null = "IS NULL",
    gt = ">",
    lt = "<",
    gteq = ">=",
    lteq = "<="
}
declare enum EQueryTypes {
    select = "SELECT",
    insert = "INSERT",
    update = "UPDATE",
    delete = "DELETE"
}
type TPaginatedTotals = {
    page: number;
    pageSize: number;
    totalPages: number;
    thisPageCount: number;
    totalCount: number;
    hasNextPage: boolean;
    hasPreviousPage: boolean;
};
interface IEnvironment {
    readonly code: string;
    readonly name: string;
    validate(): void;
    getConnection(): BaseConnection;
}

declare class Collection<T extends BaseModel> {
    data: T[];
    totals: {
        page: number;
        pageSize: number;
        totalPages: number;
        thisPageCount: number;
        totalCount: number;
        hasNextPage: boolean;
        hasPreviousPage: boolean;
    };
    constructor(modelList: T[], totalsData?: TPaginatedTotals);
    first(): T | null;
    last(): T | null;
    size(): number;
}

declare class CustomError extends Error {
    errorData?: any;
    errorMessage?: string;
    errorTarget?: any;
    constructor(errorData?: any, errorMessage?: string, target?: any);
    toString(): string;
    toJson(): {
        errorMessage: string | undefined;
        errorTarget: any;
        errorData: any;
    } | {
        errorMessage: string | undefined;
        errorData: any;
        errorTarget?: undefined;
    };
}
declare class TransactionError extends CustomError {
    constructor(errorData: any, errorMessage?: string, target?: any);
}
declare class StandardError extends CustomError {
    constructor(errorData: any, errorMessage?: string, target?: any);
}

declare abstract class BaseResource {
    protected logger: FileLogger | Console;
    protected originalLogger: FileLogger | null;
    constructor({ logger }?: {
        logger?: FileLogger | null;
    });
    abstract getLoggerExtension(): string;
}

declare abstract class BaseRestResource extends BaseResource {
    private connection;
    constructor(connection: RestTypeConnection, { logger }?: {
        logger?: FileLogger | null;
    });
    protected get(uri: string, { params, fullResponse, headers }?: {
        params?: any;
        fullResponse?: boolean;
        headers?: any;
    }): Promise<any>;
    protected post(uri: string, { params, body, fullResponse, headers }?: {
        params?: any;
        body?: any;
        fullResponse?: boolean;
        headers?: any;
    }): Promise<any>;
    protected put(uri: string, { params, body, fullResponse, headers }?: {
        params?: any;
        body?: any;
        fullResponse?: boolean;
        headers?: any;
    }): Promise<any>;
    protected delete(uri: string, { params, fullResponse, headers }?: {
        params?: any;
        fullResponse?: boolean;
        headers?: any;
    }): Promise<any>;
}

declare abstract class Query {
    queryType: EQueryTypes;
    tableName: string;
    constructor(queryType: EQueryTypes, tableName: string);
    abstract compileQuery(): {
        queryString: string;
        queryData: any;
    };
    getExecutionParams(): any;
    addJoinTable(...args: any[]): void;
    addFieldToSelect(...args: any[]): void;
    addExpressionToSelect(...args: any[]): void;
    addFieldToFilter(...args: any[]): void;
    addGroupBy(...args: any[]): void;
    addDataToUpdate(...args: any[]): void;
    addDataToInsert(...args: any[]): void;
    addLimit(...args: any[]): void;
    addOrderBy(...args: any[]): void;
}
declare abstract class FilterableQuery extends Query {
    protected fieldFilters: any[];
    whereCompiledData: {
        string: string;
        data: any;
    };
    static VALID_CONDITION_KEYS: string[];
    static isTMultipleCondition: (condition: any) => condition is TMultipelCondition;
    static isTSimpleCondition: (condition: any) => condition is TSimpleCondition;
    static isTComplexCondition: (condition: any) => condition is TComplexCondition;
    addFieldToFilter(field: string | string[], condition: TSimpleCondition | TComplexCondition | TMultipelCondition): this;
    protected checkAddFieldToFilterData(field: string | string[], condition: TSimpleCondition | TComplexCondition | TMultipelCondition): boolean;
    protected checkValidConditionArray(condition: TMultipelCondition): boolean;
    protected checkValidCondition(condition: TSimpleCondition | TComplexCondition): boolean;
    protected checkValidComplexCondition(condition: TComplexCondition): boolean;
    protected prepareFieldFilters(field: string | string[], condition: TSimpleCondition | TComplexCondition | TMultipelCondition): this;
    compileWhereData(): any;
    protected compileQueryFilter(queryFilters: any[]): any;
    protected compileLineFilter(lineFilters: {
        [fieldName: string]: any;
    }): any;
    protected compileFieldConditions(fieldName: string, conditions: (TSimpleCondition | TComplexCondition)[]): any;
    protected compileConditions(fieldName: string, condition: TSimpleCondition | TComplexCondition): {
        string: any;
        data: any[];
    };
}
declare class SelectQuery extends FilterableQuery {
    selectFieldsCompiledData: {
        string: string;
        data: any;
    };
    joinCompiledData: {
        string: string;
        data: any;
    };
    groupByCompiledData: {
        string: string;
        data: any;
    };
    limitCompiledData: {
        string: string;
        data: any;
    };
    orderByCompiledData: {
        string: string;
        data: any;
    };
    private selectFields;
    private selectExpressions;
    private joins;
    private groupBy;
    private limit;
    private orderBy;
    private nestTables;
    constructor(tableName: string);
    compileQuery(): {
        queryString: string;
        queryData: any;
    };
    getExecutionParams(): any;
    addFieldToSelect(field: string | string[] | {
        [key: string]: string;
    } | {
        [key: string]: string;
    }[]): this;
    addExpresionToSelect(expresionData: {
        [key: string]: string;
    }): this;
    addJoinTable(tableName: string | {
        [key: string]: string;
    }, fields: "*" | {
        [key: string]: string;
    }, condition: string, type?: "inner" | "left" | "right" | "outer"): this;
    addGroupBy(field: string | string[]): this;
    addLimit(limit1: number, limit2?: number): this;
    addOrderBy(orderField: string, orderType?: "ASC" | "DESC"): this;
    private checkAddFieldToSelect;
    private checkAddExpressionToSelect;
    private checkJoinTable;
    private checkAddGroupBy;
    private checkAddLimit;
    private checkAddOrderBy;
    private prepareSelectFields;
    private prepareSelectExpressions;
    private prepareJoinTable;
    private prepareGroupBy;
    private prepareLimit;
    private prepareOrderBy;
    protected compileSelectFieldsData(): {
        string: string;
        data: any;
    };
    protected compileJoinData(): {
        string: string;
        data: any;
    };
    protected compileGroupByData(): {
        string: string;
        data: any;
    };
    protected compileLimitData(): {
        string: string;
        data: any;
    };
    protected compileOrderByData(): {
        string: string;
        data: any;
    };
}
declare class InsertQuery extends Query {
    insertValuesCompiledData: {
        string: string;
        data: any;
    };
    insertFieldsCompiledData: {
        string: string;
        data: any;
    };
    private insertData;
    constructor(tableName: string);
    compileQuery(): {
        queryString: string;
        queryData: any;
    };
    addDataToInsert(insertData: {
        [key: string]: any;
    }): this;
    private checkAddDataToInsert;
    private prepareDataToInsert;
    protected compileInsertFieldsData(): {
        string: string;
        data: any;
    };
    protected compileInsertValuesData(): {
        string: string;
        data: any;
    };
}
declare class UpdateQuery extends FilterableQuery {
    updateFieldsCompiledData: {
        string: string;
        data: any;
    };
    private updateData;
    constructor(tableName: string);
    compileQuery(): {
        queryString: string;
        queryData: any;
    };
    addDataToUpdate(updateData: {
        [key: string]: any;
    }): this;
    private checkAddDataToUpdate;
    private prepareDataToUpdate;
    protected compileUpdateFieldsData(): {
        string: string;
        data: any;
    };
}
declare class DeleteQuery extends FilterableQuery {
    constructor(tableName: string);
    compileQuery(): {
        queryString: string;
        queryData: any;
    };
}

declare abstract class BaseMysqlResource<T extends BaseMysqlModel, C extends Collection<T>> extends BaseResource {
    private connection;
    tableName: string;
    primaryKeyField: string;
    protected transactionActive: boolean;
    protected transactionConnection: PoolConnection | null;
    constructor(connection: MysqlTypeConnection, tableName: string, primaryKeyField: string, { logger }?: {
        logger?: FileLogger | null;
    });
    abstract parse(modelData: any): T;
    abstract parseCollection(modelList: T[]): C;
    protected selectQuery(): SelectQuery;
    protected insertQuery(): InsertQuery;
    protected updateQuery(): UpdateQuery;
    protected deleteQuery(): DeleteQuery;
    /**
     * @section BASE FUNCTIONS
     * Functions to execute queries given previous set data
     */
    private resultToTree;
    appendToTree(currentTree: any, destinationPath: string[], newNode: any): any;
    extractExpressionsFromResults(resultList: any[]): {
        [alias: string]: any;
    };
    protected executeQuery(query: Query, parseModel?: boolean): Promise<C | {
        collection: C;
        expressions: {
            [alias: string]: any;
        };
    }>;
    transaction(process: CallableFunction): Promise<any>;
}

export { BaseModel, BaseMysqlModel, BaseMysqlResource, BaseResource, BaseRestModel, BaseRestResource, Collection, DeleteQuery, EQueryOperators, EQueryTypes, FileLogger, FilterableQuery, type IEnvironment, InsertQuery, MysqlTypeConnection, Query, RestTypeConnection, SelectQuery, StandardError, type TApiLogger, type TApiLoggerOpt, type TComplexCondition, type TFollowOptions, type TMultipelCondition, type TSimpleCondition, TransactionError, UpdateQuery, customLogger, dailyLogger, runLogger };
