import type { ExpiresAction, 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 { AuthValue, 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 'node:child_process';
import type { BinaryLike, CipherGCMTypes } from 'node:crypto';
import type { LookupAddress } from 'node:dns';
import type { AgentOptions } from 'node:http';
import type { BrotliOptions, ZlibOptions } from 'node:zlib';
// @ts-ignore
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 DownloadAction {
    bin?: string | false;
    exec?: ExecAction;
}

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

export interface HandlerSettings<T = PlainObject> {
    settings?: T & { broadcast_id?: string | 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 = NodeSettings> extends HandlerSettings<T> {
    process?: {
        cpu_usage?: boolean;
        memory_usage?: boolean;
        inline?: boolean;
    };
    require?: {
        ext?: string | string[] | boolean;
        npm?: boolean;
        inline?: boolean;
    };
    posix?: {
        strict?: boolean;
    };
}

export interface NodeSettings extends PlainObject {
    package_manager?: "npm" | "yarn" | "pnpm";
}

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

export interface ProcessEnvConfig {
    apply?: boolean;
}

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

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

export interface PermissionSettings extends PlainObject {
    picomatch?: PicomatchOptions | null;
    minimatch?: MinimatchOptions | null;
}

export interface DownloadModule<T = PlainObject> extends HandlerSettings<T>, ExpiresAction {
    aria2?: DownloadAction & {
        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";
        proxy?: {
            http: string;
            https: string;
            ftp: string;
            all: string;
        } | false;
        no_proxy?: string;
        conf_path?: string;
    };
    rclone?: DownloadAction & {
        /* Copy */
        check_first?: boolean;
        checksum?: boolean;
        combined?: string;
        csv?: boolean;
        differ?: string;
        error?: string;
        cutoff_mode?: "HARD" | "SOFT" | "CAUTIOUS";
        hash: "md5" | "SHA-1" | "DropboxHash";
        ignore_case_sync?: boolean;
        ignore_checksum?: boolean;
        ignore_existing?: boolean;
        ignore_size?: boolean;
        ignore_times?: boolean;
        immutable?: boolean;
        inplace?: boolean;
        max_backlog?: number;
        max_duration?: string;
        max_transfer?: string;
        metadata?: boolean;
        modify_window?: string;
        multi_thread_chunk_size?: string;
        multi_thread_cutoff?: string;
        multi_thread_streams?: number;
        multi_thread_write_buffer_size?: string;
        no_check_dest?: boolean;
        no_traverse?: boolean;
        no_update_dir_modtime?: boolean;
        no_update_modtime?: boolean;
        refresh_times?: boolean;
        size_only?: boolean;
        streaming_upload_cutoff?: string;
        update?: boolean;
        /* Listing */
        fast_list?: boolean;
        /* Networking */
        bind?: string;
        contimeout?: string;
        disable_http2?: boolean;
        timeout?: string;
        /* Config */
        config?: 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?: string[] | null;
    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 | string;
    user_key?: ObjectMap<DbSourceOptions>;
    imports?: StringMap;
}

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

export interface MemorySettings extends PlainObject {
    users?: boolean | string[];
    stats?: {
        file_count?: boolean;
    };
    cache_disk?: MemoryCacheDiskSettings;
    gc?: { interval?: number | string; expires_limit?: number | string } & ExpiresAction;
}

export interface MemoryCacheDiskSettings<T = number | string, U = string[] | null> extends IncludeAction<U>, ExpiresAction<T> {
    enabled?: boolean;
    min_size?: T;
    max_size?: 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;
    type?: "lru" | "lfu";
    percent?: T;
    limit?: T;
}

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;
    max_concurrent_streams?: number | string;
    agent?: {
        keep_alive?: boolean;
        keep_alive_interval?: number | string;
        timeout?: number | string;
        proxy_env?: AgentOptions["proxyEnv"];
    };
    disk?: HttpDiskSettings;
    buffer?: HttpMemorySettings;
    connect?: HttpConnectSettings;
    dns?: DnsLookupSettings;
    use?: {
        http_version?: number | string;
        accept_encoding?: boolean;
    };
    proxy?: HttpProxySettings;
    headers?: HttpOutgoingHeaders;
    certs?: ObjectMap<SecureConfig<string | string[]>>;
    post_limit?: number | string;
}

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

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;
    /** @deprecated */
    zopfli?: ZopfliOptions;
}

export interface CompressSettings extends PlainObject {
    cache?: boolean | CacheDirAction & ObjectMap<number | string | boolean>;
    /** @deprecated cache.expires */
    cache_expires?: number | string;
    gzip_level?: number | string;
    brotli_quality?: number | string;
    /** @deprecated */
    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<T = ErrorSettings> extends HandlerModule<T, ErrorOutMethod> {
    out?: string | ErrorOutMethod;
    abort?: string[];
    fatal?: boolean;
    /** @deprecated retry_limit */
    recursion_limit?: number | string;
    retry_limit?: number | string;
}

export interface ErrorSettings extends PlainObject {
    trap_exceptions?: boolean;
}

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>, W = boolean | LoggerProcessSettings> {
    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?: W;
    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 {
    enabled?: boolean;
    cpu?: boolean;
    cpu_bar?: boolean | number | number[];
    cpu_bar_color?: [typeof IBackgroundColor, typeof IBackgroundColor, typeof IBackgroundColor];
    cpu_single_core?: boolean;
    mem?: boolean;
    mem_format?: "%" | Unit;
    mem_free?: boolean;
}

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 | [string, string];
}

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

export interface HttpDiskSettings extends IncludeAction, ExpiresAction {
    enabled?: boolean;
    limit?: 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 extends ExpiresAction {
    family?: number | string;
    resolve?: ObjectMap<Partial<LookupAddress>>;
}

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

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

export interface ExecOptions extends SpawnOptions {
    command?: string;
    warn?: string | string[];
}

export interface PurgeAction {
    purge?: PurgeComponent;
}

export interface CacheDirAction extends ExpiresAction {
    enabled?: boolean;
    dir?: string;
}

export interface PoolConfig<T = number> extends MinMax {
    idle?: T;
    idle_max?: number;
    queue_max?: number;
    queue_idle?: T;
    purge?: T;
    timeout?: number;
    server_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 interface MinMax<T = number> {
    min?: T;
    max?: T;
}

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

export type { ExecAction, PermissionReadWrite, SecureConfig };