import type { DataSource, DbDataSource } from './squared';

import type { CacheOptions, IdentifierAction } from './core';
import type { AuthValue } from './http';

import type { DB_TYPE } from '../index.d';

export interface ExecuteAction<T = unknown> {
    params?: T;
}

export interface CascadeAction {
    cascade?: string;
    cacheObjectKey?: string;
    fallback?: unknown;
}

export interface ExecuteQueryOptions {
    checkObject?: CheckObjectCallback | string;
    checkObjectKey?: string;
    errorQuery?: ErrorQueryCallback;
    sessionKey?: string;
    outCacheMiss?: string[];
}

export interface ExecuteBatchQueryOptions extends ExecuteQueryOptions {
    parallel?: boolean;
    connectOnce?: boolean;
}

export interface ProcessRowsOptions {
    disconnect?: () => void;
    parallel?: boolean;
}

export interface DbConnection extends Required<AuthValue> {
    protocol: string;
    hostname: string;
    port: string;
    pathname: string;
    search: string;
    database: string;
}

export interface HandleFailOptions {
    commandType?: number;
    errorQuery?: ErrorQueryCallback;
}

export interface ServerAuth<T = number> extends AuthValue, IdentifierAction {
    protocol?: string;
    server?: string;
    hostname?: string;
    port?: T;
    database?: string;
}

export interface IDbPool<T extends DbDataSource = DbDataSource, U = unknown, V = unknown, W = unknown> {
    client: U;
    lastAccessed: number;
    success: number;
    failed: number;
    poolKey: string;
    uuidKey: AuthValue | null;
    add(item: T, uuidKey?: string): this;
    has(item: T): boolean;
    getConnection(credential?: W): Promise<V>;
    remove(): void;
    detach(force?: boolean): Promise<void>;
    close(): Promise<void>;
    isIdle(timeout: number): boolean;
    isEmpty(): boolean;
    set connected(value: boolean);
    get persist(): boolean;
    get closed(): boolean;
    get closeable(): boolean;
    set parent(value: ObjectMap<IDbPool<T>>);
}

export interface DbPoolConstructor<T extends DbDataSource = DbDataSource, U = unknown, V = unknown, W = unknown> {
    CACHE_UNUSED: readonly string[];
    CACHE_IGNORE: readonly string[];
    asString(credential: unknown): string;
    canCache(credential: unknown): boolean;
    sanitize(credential: unknown, sort?: boolean): unknown;
    removeUUIDKey<X>(credential: X & IdentifierAction): X;
    findKey<X extends IDbPool, Y extends DbDataSource>(pools: ObjectMap<X>, uuidKey: unknown, poolKey: string | undefined, ...items: Y[]): X | null;
    validateKey<X extends IDbPool>(pools: ObjectMap<X>, username: string, uuidKey: unknown): [string, X | null];
    checkTimeout<X extends IDbPool>(pools: ObjectMap<X>, value: number, limit?: number): Promise<number>;
    readonly prototype: IDbPool<T, U, V, W>;
    new(pool: U, poolKey: string, uuidKey?: AuthValue | null): IDbPool<T, U, V, W>;
}

export interface TimeoutAction {
    timeout?: number | string;
}

export type DbSource = "mariadb" | "mongodb" | "mssql" | "mysql" | "oracle" | "postgres" | "redis";
export type QueryResult = unknown[];
export type BatchQueryResult = QueryResult | null[];
export type CheckObjectCallback = (item: DataSource, data: unknown) => QueryResult | null;
export type ErrorQueryCallback = (err: unknown, item: DbDataSource, commandType?: number) => boolean;

export interface SQL_COMMAND {
    SELECT: 1;
    INSERT: 2;
    UPDATE: 3;
    DELETE: 4;
}

export type { DB_TYPE, CacheOptions, IdentifierAction };