interface PathInfo<T = string> {
    pathname?: T;
    filename?: T;
}

interface LocationUri extends Required<PathInfo> {}

interface Asset {
    uri?: string;
    mimeType?: string;
}

interface TextAsset extends Asset, LocationUri {
    content?: string;
}

interface ImageAsset extends Asset, Dimension, ResourceAction, FromAction {
    inline?: boolean;
}

interface LayoutAsset extends TextAsset {
    index: number;
    systemDefined?: boolean;
}

interface FileAsset extends TextAsset, OutputAction, DocumentAction, ResourceAction, MetadataAction, MultipartAction, FormatAction<string | string[]>, IncrementalAction, ChecksumAction {
    base64?: string;
    imported?: boolean | string[];
    flags?: number;
}

interface RawAsset extends FileAsset, Partial<ImageAsset> {
    buffer?: ArrayBuffer;
}

interface ViewEngine {
    name: string;
    options?: {
        compile?: PlainObject;
        output?: PlainObject;
    };
}

interface DataSource<T = unknown> extends ElementAction, DocumentAction {
    source: string;
    uri?: string;
    index?: number;
    limit?: number;
    query?: T;
    postQuery?: string | FunctionType;
    preRender?: string | FunctionType;
    whenEmpty?: string | FunctionType;
    removeEmpty?: boolean;
    ignoreCache?: boolean | 0;
}

interface DbDataSource<T = unknown, U = PlainObject, V = unknown> extends DataSource<T> {
    name?: string;
    table?: string;
    options?: U;
    update?: V;
    updateType?: number;
    parallel?: boolean;
    streamRow?: boolean | string;
    willAbort?: boolean;
}

interface OutputAction<T = CompressFormat[]> {
    moveTo?: string;
    commands?: string[];
    compress?: T;
    willChange?: boolean;
}

interface TaskAction {
    tasks?: TaskCommand[];
}

interface WatchAction {
    watch?: WatchValue;
}

interface WorkerAction {
    worker?: boolean | number;
}

interface BundleAction {
    bundleId?: number | string;
    bundleIndex?: number;
    bundleReplace?: unknown;
    bundleQueue?: Promise<unknown>[];
    trailingContent?: string[];
    exported?: boolean;
}

interface ChecksumAction {
    checksum?: ChecksumValue;
    checksumOutput?: ChecksumValue;
}

interface ImportAction<T = unknown> {
    imports?: T;
}

interface DocumentAction<T = string | string[]> {
    document?: T;
    encoding?: TextEncoding;
}

interface ElementAction<T = XmlTagNode> {
    element?: T;
}

interface AttributeAction<T = AttributeMap> {
    attributes?: T;
}

interface MetadataAction<T = PlainObject> {
    metadata?: T | null;
}

interface StorageAction<T = unknown> {
    cloudStorage?: T[];
}

interface HashAction {
    hash?: string;
}

interface ExcludeAction {
    exclude?: boolean;
}

interface ObserveAction<T = FunctionType> {
    observe?: T;
}

interface FormatAction<T = string> {
    format?: T;
}

interface TextAction {
    textContent?: string;
}

interface MultipartAction {
    formData?: BlobValue;
}

interface IncrementalAction {
    incremental?: boolean | IncrementalMatch;
}

interface FromAction {
    from?: string[];
}

interface ExpiresAction<T = number | string> {
    expires?: T;
}

interface ContentAction extends Omit<DataURL, "data"> {}

interface ResourceAction extends TaskAction, WatchAction {
    wbnUri?: string;
}

interface BlobValue extends KeyValue<string, unknown> {
    filename?: string;
}

interface TaskCommand<T = unknown> {
    handler: string;
    task: T;
    preceding?: boolean;
}

interface TagData {
    tagName: string;
    tagCount?: number;
    tagIndex?: number;
}

interface TagAppend extends TagData, TextAction {
    order: number;
    id?: string;
    prepend?: boolean;
    nextSibling?: number;
}

interface TagLocator {
    id: string;
    index?: number;
    count?: number;
}

interface XmlNode extends AttributeAction {
    index: number;
    outerXml?: string;
    innerXml?: string;
    dynamic?: boolean;
    ignoreCase?: boolean;
}

interface XmlTagNode extends XmlNode, TagData, TextAction {
    id?: StringMap;
    locator?: TagLocator;
    append?: TagAppend;
    depth?: number;
}

interface WebSocketClient<T = string> {
    socketId?: T;
    port?: number;
    secure?: boolean;
}

interface WebSocketConnection extends Required<WebSocketClient> {
    expired: number;
}

interface WebSocketResponse {
    event?: string;
    socketId?: string | string[];
    type?: string;
    value?: unknown;
    timeStamp?: number;
    status?: LogStatus[];
    errors?: string[];
}

interface WatchResponse extends WebSocketResponse {
    event: "modified" | "broadcast" | WebSocketEvent;
    action?: string;
    url?: {
        pathname: string;
        search?: string;
    };
    always?: boolean;
}

interface BroadcastResponse extends WebSocketResponse {
    event: "broadcast" | WebSocketEvent;
    options?: unknown;
}

interface BroadcastSocket extends WebSocketClient<string | string[]> {
    callback?: BroadcastMessageCallback;
}

interface WatchInterval extends TaskBase {
    id?: string;
    main?: boolean;
    reload?: WatchReload | boolean;
    recursive?: boolean | string | string[];
}

interface WatchReload extends WebSocketClient {
    module?: boolean;
    always?: boolean;
    on?: {
        message: string;
        open?: string;
        error?: string;
        close?: string;
    };
}

interface Exclusions extends PathInfo<string[]> {
    glob?: string[];
    extension?: string[];
    pattern?: Array<string | RegExp>;
}

interface CompressLevel {
    level?: number;
    chunkSize?: number;
    mimeType?: string;
}

interface CompressFormat extends CompressLevel, FormatAction, WorkerAction {
    condition?: string;
    plugin?: string;
    options?: PlainObject;
}

interface FileInfo {
    name: string;
    size: number | string;
}

interface RequestBase {
    baseUrl?: string;
    priority?: number;
    broadcastId?: string | string[];
    error?: { abort?: boolean | string | string[]; fatal?: boolean };
    ignoreExtensions?: boolean | string | string[];
}

interface RequestData<T = FileAsset> extends RequestBase, ImportAction<StringMap>, IncrementalAction {
    projectId?: string;
    assets?: T[];
    dataSource?: DataSource[];
    document?: string[];
    task?: string[];
    modules?: string[];
    update?: WatchInterval;
    checksum?: string | boolean | 1 | ChecksumOutput;
    headers?: OutgoingHeaders;
    watch?: boolean;
    cache?: boolean | AnyObject;
    log?: boolean | string | string[] | LogOptions;
    auth?: unknown;
    authProvider?: string;
}

interface LogOptions {
    enabled?: boolean;
    exclude?: string | string[];
    useColor?: boolean;
    useNumeric?: boolean;
    showSize?: boolean;
    showProgress?: boolean;
    showDiff?: string[];
}

interface ResponseData<T = unknown> extends PathInfo {
    success: boolean;
    data?: T;
    downloadKey?: string;
    downloadUrl?: string;
    bytes?: number;
    files?: Array<string | FileInfo>;
    status?: LogStatus[];
    error?: ResponseError;
}

interface LogStatus {
    name: string;
    type: number;
    value: string;
    timeStamp: number;
    from: string;
    sessionId: string;
    duration?: number;
    source?: string;
}

interface ResponseError {
    message: string;
    hint?: string;
}

interface OutputCommand extends PathInfo, DocumentAction, OutputAction<string | CompressFormat | CompressFormat[]>, AttributeAction, HashAction, StorageAction, ResourceAction, MetadataAction {
    selector?: string;
    type?: string;
    process?: string[];
    ignoring?: string[];
    bundleId?: number | string;
    rewrite?: boolean | URLData;
}

interface AuthData extends PlainObject {
    token?: string;
    default?: unknown;
}

interface ChecksumBase<T = string> {
    algorithm?: string;
    digestEncoding?: T;
}

interface ChecksumOutput<T = string> extends ChecksumBase<T> {
    filename?: string;
    include?: string | string[];
    exclude?: string | string[];
    recursive?: boolean | 1;
}

interface TaskBase extends ExpiresAction {
    interval?: number | string;
    start?: number | string;
}

type WebSocketEvent = "close" | "error";
type IncrementalMatch = "none" | "staging" | "etag" | "exists";
type OutgoingHeaders = Record<string, string>;
type WebSocketMessageChange = (ev: MessageEvent, target: HTMLElement) => void;
type BroadcastMessageCallback = (result: BroadcastResponse) => void;
type ChecksumValue = string | ChecksumBase & { value?: string };
type WatchValue = boolean | WatchInterval;