import { Component } from 'vue';
import { DefineComponent } from 'vue';

export declare const ACTION_INSERT_CHILD = "insert-child";

declare const ACTION_INVOKE = "invoke";

export declare const ACTION_MOUNT = "mount";

export declare const ACTION_REMOVE_CHILD = "remove-child";

export declare const ACTION_UPDATE_PROPERTIES = "update-properties";

export declare const ACTION_UPDATE_TEXT = "update-text";

export declare interface Channel {
    <A extends RunnerAction>(action: A, ...payload: RunnerPayload<A>): void | Promise<void>;
}

export declare const createProvider: (components?: {
    [key: string]: Component<{}>;
}) => Provider;

export declare function createReceiver(): Receiver;

declare type EventHandler = () => void;

export declare const HostedTree: DefineComponent<{
    provider: Provider;
    receiver: Receiver;
}>;

declare type Id = string;

declare type InvokeHandler = (method: string, payload: unknown[]) => void;

export declare const KIND_COMMENT = "comment";

export declare const KIND_COMPONENT = "component";

export declare const KIND_FRAGMENT = "fragment";

export declare const KIND_ROOT = "root";

export declare const KIND_TEXT = "text";

declare interface Provider {
    get (type: string): Component<NonNullable<unknown>>;
}

export declare type Received = ReceivedChild | ReceivedFragment | ReceivedRoot;

export declare type ReceivedChild = ReceivedComment | ReceivedComponent | ReceivedText;

export declare interface ReceivedComment extends SerializedComment {
    version: number;
}

export declare interface ReceivedComponent<Properties extends Unknown = Unknown> extends SerializedComponent<Properties> {
    children: ReceivedChild[];
    version: number;
}

export declare interface ReceivedFragment extends SerializedFragment {
    children: ReceivedChild[];
    version: number;
}

export declare type ReceivedParent = ReceivedComponent | ReceivedFragment | ReceivedRoot;

export declare interface ReceivedRoot extends SerializedRoot {
    children: ReceivedChild[];
    version: number;
}

export declare interface ReceivedText extends SerializedText {
    version: number;
}

export declare interface ReceivedTree {
    readonly root: ReceivedRoot;
    get<T extends Received>({ id }: Pick<T, 'id'>): T | null;
    invokable<T extends Received>({ id }: Pick<T, 'id'>, handler: InvokeHandler): () => void;
    updatable<T extends Received>({ id }: Pick<T, 'id'>, handler: UpdateHandler<T>): () => void;
}

export declare interface Receiver {
    readonly receive: Channel;
    readonly tree: ReceivedTree;
    readonly state: 'mounted' | 'unmounted';
    on(event: 'mount', handler: EventHandler): () => void;
    flush(): Promise<void>;
}

export declare const ROOT_ID = "~";

declare interface Runner {
    mount(children: SerializedChild[]): void;
    insertChild(parentId: Id, after: number, child: SerializedChild, oldParentId: Id | false): void;
    removeChild(parentId: Id, at: number): void;
    updateProperties(id: Id, properties: Unknown): void;
    updateText(id: Id, text: string): void;
    invoke(id: Id, method: string, payload: unknown[], resolve: (result: unknown) => void, reject: (reason?: unknown) => void): void;
}

declare type RunnerAction = keyof RunnerActionMap;

declare interface RunnerActionMap {
    [ACTION_MOUNT]: Runner['mount'];
    [ACTION_INSERT_CHILD]: Runner['insertChild'];
    [ACTION_REMOVE_CHILD]: Runner['removeChild'];
    [ACTION_UPDATE_PROPERTIES]: Runner['updateProperties'];
    [ACTION_UPDATE_TEXT]: Runner['updateText'];
    [ACTION_INVOKE]: Runner['invoke'];
}

declare type RunnerPayload<T extends RunnerAction> = Parameters<RunnerActionMap[T]>;

declare type SerializedChild = SerializedComment | SerializedComponent | SerializedText;

declare interface SerializedComment {
    id: Id;
    kind: typeof KIND_COMMENT;
    text: string;
}

declare interface SerializedComponent<Properties extends Unknown = Unknown> {
    id: Id;
    kind: typeof KIND_COMPONENT;
    type: string;
    properties: Properties;
    children: SerializedChild[];
}

declare interface SerializedFragment {
    id: Id;
    kind: typeof KIND_FRAGMENT;
    children: SerializedChild[];
}

declare interface SerializedRoot {
    id: typeof ROOT_ID;
    kind: typeof KIND_ROOT;
    children: SerializedChild[];
}

declare interface SerializedText {
    id: Id;
    kind: typeof KIND_TEXT;
    text: string;
}

declare type Unknown = Record<string, unknown>

export declare type UpdateHandler<T extends Received = Received> = (value: T) => void;

export { }
