import type { ExtensionRequest, FileActionResult, LoadConfigInherit, Node, RootElement, TargetElement } from './base';

import { prefetch } from './lib/css';

type IncrementalData = ObjectMap<boolean | IncrementalMatch>;

export interface FileActionConfig extends DocumentAction<string> {
    uri?: boolean | string;
    key?: string;
    inherit?: LoadConfigInherit;
    pathname?: string;
    modify?: boolean;
    mimeType?: string;
    dataSource?: DataSource | DataSource[];
    partial?: boolean;
    cache?: boolean;
}

export interface FileActionOptions extends RequestData, PlainObject {
    pid?: number;
    fetchMode?: RequestMode;
    timeout?: number;
    config?: FileActionConfig | boolean | string;
    incrementalMap?: {
        pathname?: IncrementalData;
        extension?: IncrementalData;
        mime?: IncrementalData;
        overwrite?: boolean;
    };
    outgoing?: OutgoingHeaders;
    exclusions?: Exclusions | Array<string | RegExp>;
    broadcast?: BroadcastSocket | BroadcastMessageCallback;
    throwErrors?: boolean;
    filter?: (item: FileAsset, index: number, array: FileAsset[]) => unknown;
}

export interface PrefetchItem {
    src: string;
    data: string | Blob | null;
    type?: "css" | "javascript" | "image" | "svg" | "audio" | "video";
    error?: unknown;
}

export interface ObserveSocket {
    element: HTMLElement;
    socket: WebSocket | null;
    close(): void;
    get readyState(): number;
}

export interface FileObserveOptions extends WebSocketClient, ExpiresAction {
    action?: "reload" | "hot";
    throwErrors?: boolean;
}

export type FileBroadcastOptions = WebSocketClient & { hostname?: string; socketKey?: string };
export type ExtensionRequestObject = ExtensionRequest<Node> | [ExtensionRequest<Node>, PlainObject];
export type AddressValue = string | URL | Location;

export const settings: AnyObject;
export function setHostname(value: string): void;
export function setEndpoint(name: string, value: string): void;
export function setLocalAddress(...values: AddressValue[]): void;
export function setFramework(value: PlainObject, loadName: string, cache?: boolean): void;
export function setFramework(value: PlainObject, options?: PlainObject, cache?: boolean): void;
export function setFramework(value: PlainObject, options?: PlainObject, saveName?: string, cache?: boolean): void;
export function add(...values: ExtensionRequestObject[]): number;
export function remove(...values: ExtensionRequest<Node>[]): number;
export function get(value: string): PlainObject | undefined;
export function get(...values: string[]): PlainObject[];
export function attr(name: ExtensionRequest<Node>, attrName: string, value?: unknown, append?: boolean): unknown;
export function apply(value: ExtensionRequest<Node>, saveAs: string): boolean;
export function apply(value: ExtensionRequest<Node>, options: PlainObject, saveAs?: string): boolean;
export function extend(functionMap: PlainObject, framework?: number): void;
export function parseDocument(...elements: RootElement[]): Promise<Node | Node[] | void>;
export function parseDocumentSync(...elements: RootElement[]): Node | Node[] | void;
export function latest(value?: 1 | -1): string;
export function latest(value: number): string[];
export function auth(...args: unknown[]): void;
export function close(projectId?: string): Promise<boolean>;
export function save(timeout: number): FileActionResult;
export function save(projectId: string | undefined, timeout: number): FileActionResult;
export function save(projectId?: string, broadcastId?: string): FileActionResult;
export function reset(projectId?: string): void;
export function saveAs(value: string, setting: string): FileActionResult;
export function saveAs(value: string, options?: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function appendTo(value: string, setting: string): FileActionResult;
export function appendTo(value: string, options?: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function copyTo(value: string | string[], setting: string): FileActionResult;
export function copyTo(value: string | string[], options?: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function saveFiles(value: string, setting: string): FileActionResult;
export function saveFiles(value: string, options: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function appendFiles(value: string, setting: string): FileActionResult;
export function appendFiles(value: string, options: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function copyFiles(value: string | string[], setting: string): FileActionResult;
export function copyFiles(value: string | string[], options: FileActionOptions, setting?: string, overwrite?: boolean): FileActionResult;
export function kill(timeout: string): Promise<number>;
export function kill(pid?: number, timeout?: number | string): Promise<number>;
export function findDocumentNode(value: TargetElement, all: true): Node[];
export function findDocumentNode(value: TargetElement, projectId?: string): Node | undefined;
export function findDocumentNode(value: TargetElement, all?: boolean | string, projectId?: string): Node | undefined;
export function getElementById(value: string, sync: true, cache?: boolean): Node | null;
export function getElementById(value: string, sync?: boolean, cache?: boolean): Promise<Node> | null;
export function querySelector(value: string, sync: true, cache?: boolean): Node | null;
export function querySelector(value: string, sync?: boolean, cache?: boolean): Promise<Node> | null;
export function querySelectorAll(value: string, sync: true, cache?: boolean): Node[];
export function querySelectorAll(value: string, sync?: boolean, cache?: boolean): Promise<Node[]> | null;
export function fromElement(element: TargetElement, sync: true, cache?: boolean): Node | null;
export function fromElement(element: TargetElement, sync?: boolean, cache?: boolean): Promise<Node> | null;
export function fromNode(node: Node, sync: true, cache?: boolean): Node | null;
export function fromNode(node: Node, sync?: boolean, cache?: boolean): Promise<Node> | null;
export function observe(value?: boolean | MutationObserverInit): void;
export function observeSrc<T extends HTMLElement | string>(element: T, options: FileObserveOptions): Promise<T extends string ? ObserveSocket[] : ObserveSocket>;
export function observeSrc<T extends HTMLElement | string>(element: T, callback: WebSocketMessageChange, options?: FileObserveOptions): Promise<T extends string ? ObserveSocket[] : ObserveSocket>;
export function broadcast(callback: BroadcastMessageCallback, socketId: string): boolean;
export function broadcast(callback: BroadcastMessageCallback, options: FileBroadcastOptions): boolean;
export function clear(): void;
export function toString(): string;
export { prefetch };

export * as lib from './lib';
export * as base from './base';
export * as svg from './svg';

export as namespace squared;