import type { WatchInterval } from './squared';

import type { HashAlgorithm } from './asset';
import type { CloudSource } from './cloud';
import type { PermissionAction, PermissionReadWrite, PermittedDirectories } from './core';
import type { DbSource, TimeoutAction } from './db';
import type { HttpOutgoingHeaders, SecureConfig, ServerPort } from './http';
import type { BackgroundColor, BroadcastOutMethod, ErrorOutMethod, ForegroundColor, LoggerColor, LoggerStatus, TextAlign, TextWrapStyle } from './logger';
import type { ExecAction, IncludeAction } from './module';

import type { SpawnOptions } from 'child_process';
import type { BinaryLike, CipherGCMTypes } from 'crypto';
import type { LookupAddress } from 'dns';
import type { BrotliOptions, ZlibOptions } from 'zlib';

import type { BackgroundColor as IBackgroundColor } from 'chalk';
// @ts-ignore
import type { Unit } from 'bytes';
// @ts-ignore
import type { MinimatchOptions } from 'minimatch';
// @ts-ignore
import type { Options as ZopfliOptions } from 'node-zopfli';
// @ts-ignore
import type { PicomatchOptions } from 'picomatch';

export interface HandlerModule<T = PlainObject> extends HandlerSettings<T> {
    handler?: string;
    extensions?: string[];
}

export interface HandlerSettings<T = PlainObject> {
    settings?: T & { broadcast_id?: ArrayOf<string> };
}

export interface ClientModule<T = ClientSettings> extends HandlerModule<T>, PermissionAction {}

export interface ClientSettings<T = PlainObject> extends PlainObject {
    users?: ObjectMap<T>;
    cache_dir?: string;
}

export interface NodeModule<T = PlainObject> extends HandlerSettings<T> {
    process?: {
        cpu_usage?: boolean;
        memory_usage?: boolean;
        inline?: boolean;
    };
    require?: {
        ext?: ArrayOf<string> | boolean;
        npm?: boolean;
        inline?: boolean;
    };
}

export interface ProcessModule<T = PlainObject> extends HandlerSettings<T> {
    env?: ProcessEnvConfig;
    thread?: {
        admin: {
            users?: string[];
            private?: boolean;
        };
        queue?: {
            limit?: number | string;
            expires?: number | string;
            priority: { bypass?: number | string } & MinMax<number | string>;
        };
        limit?: number | string;
        sub_limit?: number | string;
        expires?: number | string;
    };
    cipher?: CipherConfig;
    password?: string;
}

export interface ProcessEnvConfig {
    apply?: boolean;
}

export interface TempModule<T = PlainObject> extends HandlerSettings<T> {
    dir?: string;
    env?: string;
    write?: boolean;
}

export interface PermissionModule<T = PermissionSettings> extends PermittedDirectories, HandlerSettings<T> {
    home_read?: boolean;
    home_write?: boolean;
    process_exec?: (string | ExecOptions)[];
}

export interface PermissionSettings extends PlainObject {
    picomatch?: Null<PicomatchOptions>;
    minimatch?: Null<MinimatchOptions>;
}

export interface DownloadModule<T = PlainObject> extends HandlerSettings<T> {
    expires?: number | string;
    aria2?: {
        bin?: string | false;
        exec?: ExecAction;
        check_integrity?: boolean;
        update_status?: number | string | { interval?: number | string; broadcast_only?: boolean };
        max_concurrent_downloads?: number | string;
        max_connection_per_server?: number | string;
        bt_stop_timeout?: number | string;
        bt_tracker_connect_timeout?: number | string;
        bt_tracker_timeout?: number | string;
        min_split_size?: string;
        disk_cache?: number | string;
        lowest_speed_limit?: number | string;
        always_resume?: boolean;
        file_allocation?: "none" | "prealloc" | "trunc" | "falloc";
        conf_path?: string;
    };
}

export interface DocumentModule<T = DocumentSettings, U = DbSettings> extends ClientModule<T> {
    eval?: DocumentEval;
    imports?: StringMap;
    versions?: StringMap;
    format?: AnyObject;
    db?: DbModule<U>;
}

export interface DocumentEval {
    function?: boolean;
    absolute?: boolean;
}

export interface DocumentGroup<T = { imports?: StringMap } & AnyObject, U = AnyObject> {
    transform?: T;
    view_engine?: U;
    pages?: ObjectMap<AnyObject>;
    imports?: StringMap;
}

export interface DocumentUserSettings<T = AnyObject, U = T> extends DocumentGroup<T, U>, PlainObject {
    extensions?: Null<string[]>;
    imports_strict?: boolean;
}

export interface DocumentComponent<T = boolean, U = T, V = U> extends Omit<DocumentGroup<T, U>, "pages"> {
    cloud?: V;
}

export interface DocumentComponentOption<T = unknown> {
    cache?: T;
    coerce?: boolean;
    abort?: boolean;
    local_file?: number | string;
}

export interface DocumentSettings<T extends DocumentUserSettings = DocumentUserSettings> extends DocumentGroup, PurgeAction, ClientSettings<T>, PlainObject {
    directory?: DocumentDirectory;
    options?: DocumentComponentOptions;
    imports_strict?: boolean;
}

export interface DocumentDirectory extends StringMap {
    package?: string;
}

export type DocumentComponentOptions = DocumentComponent<DocumentComponentOption<DocumentTransform>, DocumentComponentOption<boolean>>;

export interface ClientDbSettings<T = PlainObject> extends ClientSettings<T>, PurgeAction {
    session_expires?: number;
    user_key?: ObjectMap<DbSourceOptions>;
    imports?: StringMap;
}

export interface MemoryModule<T = MemorySettings> extends HandlerSettings<T>, Record<string, Undef<T | ObjectMap<PurgeBase>>> {}

export interface MemorySettings extends PlainObject {
    users?: boolean | string[];
    cache_disk?: MemoryCacheDiskSettings;
}

export interface MemoryCacheDiskSettings<T = number | string> extends IncludeAction<Null<string[]>> {
    enabled?: boolean;
    min_size?: T;
    max_size?: T;
    expires?: T;
}

export interface DbModule<T = DbSettings> extends ClientModule<T>, DbSourceDataType<ObjectMap<AnyObject>>, PlainObject {
    apiVersion?: string;
}

export interface DbSettings<T = DbUserSettings> extends ClientDbSettings<T>, DbSourceDataType<DbSourceOptions> {}

export interface DbUserSettings extends DbSourceDataType<{ commands?: ObjectMap<ObjectMap<PlainObject>> }>, PlainObject {}

export interface DbCacheSettings extends TimeoutAction {
    dir?: string;
    purge?: number | string;
    when_empty?: boolean;
}

export interface DbSourceOptions {
    pool?: PoolConfig<number | string>;
    cache?: DbCacheValue;
    coerce?: DbCoerceValue;
}

export interface DbCoerceSettings<T = boolean> {
    credential?: T;
    options?: T;
}

export interface PurgeBase<T = number | string> extends MinMax {
    enabled?: boolean;
    percent?: T;
    limit?: number;
}

export interface PurgeComponent extends PurgeBase {
    interval?: number | string;
    all?: boolean | number;
    log?: boolean;
    prefix?: string;
}

export type DbCacheValue = number | string | DbCacheSettings;
export type DbCoerceValue = boolean | DbCoerceSettings;
export type DbSourceDataType<T = unknown> = {
    [K in DbSource]?: T;
};

export type ImageModule<T = ImageSettings> = ClientModule<T>;

export interface ImageSettings extends PlainObject {
    cache?: boolean;
    webp?: {
        path?: string;
        cwebp?: string[];
        gif2webp?: string[];
    };
}

export interface RequestModule<T = RequestSettings> extends HandlerSettings<T>, HttpHostSettings {
    timeout?: number | string;
    read_timeout?: number | string;
    agent?: {
        keep_alive?: boolean;
        timeout?: number | string;
    };
    disk?: HttpDiskSettings;
    buffer?: HttpMemorySettings;
    connect?: HttpConnectSettings;
    dns?: DnsLookupSettings;
    use?: {
        http_version?: number | string;
        accept_encoding?: boolean;
    };
    proxy?: HttpProxySettings;
    headers?: HttpOutgoingHeaders;
    certs?: ObjectMap<SecureConfig<ArrayOf<string>>>;
    post_limit?: number | string;
}

export interface HttpProxySettings extends AuthValue, IncludeAction {
    address?: string;
    port?: number | string;
    origin?: string;
    keep_alive?: boolean;
}

export interface HttpHostSettings {
    localhost?: string[];
    protocol?: {
        "http/1.1"?: string[];
        h2c?: string[];
        h2?: string[];
    };
    write_stream?: ObjectMap<number | string>;
}

export interface RequestSettings extends PurgeAction, PlainObject {
    time_format?: "readable" | "relative" | "none";
}

export interface WatchModule<T = WatchSettings> extends HandlerModule<T>, ServerInfo {
    interval?: number | string;
}

export interface WatchSettings<T = WatchUserSettings> extends ClientSettings<ObjectMap<T>>, PlainObject {}

export interface CompressModule<U = CompressSettings> extends HandlerSettings<U> {
    gzip?: ZlibOptions;
    brotli?: BrotliOptions;
    zopfli?: ZopfliOptions;
}

export interface CompressSettings extends PlainObject {
    cache?: boolean;
    cache_expires?: number | string;
    gzip_level?: number | string;
    brotli_quality?: number | string;
    zopfli_iterations?: number | string;
    chunk_size?: number | string;
}

export interface TaskModule<T = PlainObject> extends ClientModule<T>, PlainObject {}

export interface CloudModule<T = CloudSettings> extends ClientModule<T>, CloudServiceDataType<ObjectMap<AnyObject>>, PlainObject {
    apiVersion?: string;
}

export interface CloudSettings extends ClientDbSettings, CloudServiceDataType<CloudServiceOptions> {}

export type CloudServiceDataType<T = unknown> = {
    [K in CloudSource]?: T;
};

export interface CloudServiceOptions extends DbSourceOptions {
    auth?: CloudAuthSettings;
}

export interface CloudAuthSettings {
    storage?: boolean;
    database?: boolean;
}

export interface ErrorModule extends HandlerModule {
    out?: string | ErrorOutMethod;
    abort?: string[];
    fatal?: boolean;
    recursion_limit?: number | string;
}

export interface LoggerProgress extends LoggerFormatColor {
    scroll_buffer?: number | string;
    max_width?: number | string;
    use_color?: boolean;
    text_wrap?: TextWrapStyle;
    box_char?: string;
    raw_mode?: boolean;
}

export interface LoggerModule<T = number | string, U = boolean | T, V = LoggerFormat<T>> {
    enabled?: boolean;
    level?: number | string;
    production?: string[];
    format?: LoggerFormatSettings<V>;
    progress?: LoggerProgress;
    meter?: LoggerMeterSettings<T>;
    broadcast?: BroadcastServer & { color?: boolean };
    status?: boolean | LoggerStatus;
    color?: boolean;
    session_id?: U;
    message?: boolean;
    stack_trace?: boolean | T;
    abort?: boolean;
    stdout?: boolean;
    unknown?: boolean | LoggerColor;
    system?: boolean | LoggerColor;
    node?: boolean | LoggerColor;
    process?: boolean | LoggerProcessSettings;
    image?: boolean | LoggerColor;
    compress?: boolean | LoggerColor;
    watch?: boolean | LoggerColor;
    file?: boolean | LoggerColor;
    cloud?: boolean | LoggerColor;
    db?: boolean | LoggerColor;
    time_elapsed?: boolean | LoggerColor;
    time_process?: boolean | LoggerColor;
    exec?: boolean | LoggerColor;
    http?: boolean | LoggerColor;
}

export interface LoggerFormatSettings<T = PlainObject> {
    title?: T;
    value?: T;
    hint?: T & { unit?: "auto" | "s" | "ms" };
    session_id?: T;
    message?: T;
    meter?: T;
    error?: T;
}

export interface LoggerMeterSettings<T = number | string> {
    http?: T;
    image?: T;
    compress?: T;
    process?: T;
}

export interface LoggerProcessSettings extends LoggerColor {
    cpu?: boolean;
    cpu_bar?: boolean | ArrayOf<number>;
    cpu_bar_color?: [typeof IBackgroundColor, typeof IBackgroundColor, typeof IBackgroundColor];
    cpu_single_core?: boolean;
    mem?: boolean;
    mem_format?: "%" | Unit;
}

export interface LoggerFormatColor {
    color?: ForegroundColor;
    bg_color?: BackgroundColor;
}

export interface LoggerFormat<T = number | string> extends LoggerFormatColor {
    width?: T;
    alt_color?: ForegroundColor;
    bg_alt_color?: BackgroundColor;
    bold?: boolean;
    justify?: TextAlign;
    unit?: string;
    as?: StringMap;
    braces?: string | TupleOf<string>;
}

export interface HttpSettings {
    version?: number | string;
    timeout?: number | string;
    headers?: HttpOutgoingHeaders;
    certs?: ObjectMap<SecureConfig<ArrayOf<string>>>;
}

export interface HttpDiskSettings extends IncludeAction {
    enabled?: boolean;
    limit?: number | string;
    expires?: number | string;
}

export interface HttpMemorySettings extends HttpDiskSettings {
    limit_all?: number | string;
    to_disk?: number | string | [number | string, (number | string)?];
    purge_amount?: number | string;
}

export interface HttpConnectSettings {
    timeout?: number | string;
    retry_wait?: number | string;
    retry_after?: number | string;
    retry_limit?: number | string;
    redirect_limit?: number | string;
}

export interface DnsLookupSettings {
    family?: number | string;
    expires?: number | string;
    resolve?: ObjectMap<Partial<LookupAddress>>;
}

export interface HashConfig extends IncludeAction<ObjectMap<string[] | "*">> {
    enabled?: boolean;
    algorithm?: HashAlgorithm;
    etag?: boolean;
    expires?: number | string;
    renew?: boolean;
    limit?: number | string;
}

export interface BroadcastServer extends ServerInfo<ArrayOf<number | string>> {
    out?: string | BroadcastOutMethod;
}

export interface ExecOptions extends SpawnOptions {
    command?: string;
    warn?: ArrayOf<string>;
}

export interface PurgeAction {
    purge?: PurgeComponent;
}

export interface PoolConfig<T = number> extends MinMax {
    idle?: T;
    queue_max?: number;
    queue_idle?: T;
    purge?: T;
    timeout?: number;
    socket_timeout?: number;
}

export interface CipherConfig {
    algorithm?: CipherGCMTypes;
    key?: BinaryLike;
    iv?: BinaryLike;
}

export interface ServerInfo<T = number | string> extends ServerPort<T> {
    enabled?: boolean;
    secure?: SecureConfig & ServerPort<T>;
}

export type WatchUserSettings = ObjectMap<WatchInterval>;
export type DocumentTransform = Null<boolean | "etag" | HashAlgorithm | HashConfig>;

export type { ExecAction, PermissionReadWrite, SecureConfig };