
// generated by vicinae figura codegen - do not edit manually

interface JsonRpcMessage {
	jsonrpc: "2.0";
	method?: string;
	id?: number;
	params?: Record<string, any>;
	result?: any;
	error?: any;
}

interface ITransport {
	send(data: string): void;
}

type EventSubscription = {
	unsubscribe: () => void;
};

export class RpcTransport {
	constructor(private readonly transport: ITransport) { }

	dispatchMessage(data: string) {
		const msg = JSON.parse(data) as JsonRpcMessage;

		if (msg.id !== undefined) {
			const handler = this.requestMap.get(msg.id);

			if (handler) {
				if (msg.error) handler.reject(msg.error);
				else handler.resolve(msg.result);
				this.requestMap.delete(msg.id);
			}
		}
		if (msg.id === undefined && msg.method) {
			for (const cb of this.handlers.get(msg.method) ?? []) {
				cb(msg.params);
			}
		}
	}

	request<T>(method: string, params: Record<string, any>): Promise<T> {
		const id = this.id++;
		const promise = new Promise<T>((resolve, reject) => {
			this.requestMap.set(id, { resolve: (msg) => resolve(msg as T), reject });
		});

		this.sendMessage({ jsonrpc: '2.0', id, method, params });

		return promise;
	}

	subscribe(method: string, cb: (result: any) => void): EventSubscription {
		const handlers = this.handlers.get(method);

		if (handlers) handlers.push(cb);
		else this.handlers.set(method, [cb]);

		return {
			unsubscribe: () => {
				const handlers = this.handlers.get(method);

				if (handlers) {
					handlers.splice(handlers.indexOf(cb), 1);
				}
			},
		};
	}

	private sendMessage(msg: JsonRpcMessage) {
		this.transport.send(JSON.stringify(msg));
	}


	private id = 1;
	private requestMap = new Map<number, { resolve: (value: any) => void, reject: (error: any) => void }>;
	private handlers = new Map<string, Array<(result: any) => void>>;
};

export type DMenuOutputFormat = 'Data' | 'Index';

export type PingResponse = {
	version: string;
	pid: number;
}

export type DeeplinkRequest = {
	url: string;
}

export type DeeplinkResponse = {
	error?: string;
}

export type DescribeResponse = {
	open: boolean;
	entrypoint: string;
}

export type LaunchAppRequest = {
	appId: string;
	args: string[];
	newInstance: boolean;
}

export type LaunchAppResponse = {
	error?: string;
	focusedWindowTitle: string;
}

export type LaunchCommandRequest = {
	entrypoint: string;
	args: string[];
	cwd?: string;
	query?: string;
}

export type LaunchCommandResponse = {
	error?: string;
}

export type CommandInfo = {
	id: string;
	name: string;
}

export type ListCommandsResponse = {
	commands: CommandInfo[];
}

export type DMenuRequest = {
	rawContent: string;
	navigationTitle?: string;
	placeholder?: string;
	format: DMenuOutputFormat;
	sectionTitle?: string;
	noSection: boolean;
	noQuickLook: boolean;
	noIcon: boolean;
	noMetadata: boolean;
	query?: string;
	width?: number;
	height?: number;
	noFooter: boolean;
}

export type DMenuResponse = {
	output: string;
}

export type BrowserInitRequest = {
	id: string;
	name: string;
	engine: string;
}

export type BrowserTabInfo = {
	id: number;
	windowId: number;
	title: string;
	url: string;
	active: boolean;
	muted: boolean;
	audible: boolean;
	lastAccessed: number;
}

export type FocusTabRequest = {
	tabId: number;
}

export type CloseTabRequest = {
	tabId: number;
}

export type FileResult = {
	path: string;
	score: number;
	category: string;
	mimeType?: string;
}

export type FsQueryParams = {
	limit: number;
	category?: string;
}

class IpcService {
	constructor(private readonly transport: RpcTransport) {}

	ping(): Promise<PingResponse> {
		return this.transport.request("Ipc/ping", { });	
	}

	deeplink(req: DeeplinkRequest): Promise<DeeplinkResponse> {
		return this.transport.request("Ipc/deeplink", { req});	
	}

	describe(): Promise<DescribeResponse> {
		return this.transport.request("Ipc/describe", { });	
	}

	launchApp(req: LaunchAppRequest): Promise<LaunchAppResponse> {
		return this.transport.request("Ipc/launchApp", { req});	
	}

	listCommands(): Promise<ListCommandsResponse> {
		return this.transport.request("Ipc/listCommands", { });	
	}

	launchCommand(req: LaunchCommandRequest): Promise<LaunchCommandResponse> {
		return this.transport.request("Ipc/launchCommand", { req});	
	}

	dmenu(req: DMenuRequest): Promise<DMenuResponse> {
		return this.transport.request("Ipc/dmenu", { req});	
	}

	browserInit(req: BrowserInitRequest): Promise<void> {
		return this.transport.request("Ipc/browserInit", { req});	
	}

	browserTabsChanged(tabs: BrowserTabInfo[]): Promise<void> {
		return this.transport.request("Ipc/browserTabsChanged", { tabs});	
	}

	fsQuery(q: string, params: FsQueryParams): Promise<FileResult[]> {
		return this.transport.request("Ipc/fsQuery", { q, params});	
	}

	focusTab(handler: (req: FocusTabRequest) => void): EventSubscription {
		return this.transport.subscribe("Ipc/focusTab", (msg) => handler(msg.req))
	}
	closeTab(handler: (req: CloseTabRequest) => void): EventSubscription {
		return this.transport.subscribe("Ipc/closeTab", (msg) => handler(msg.req))
	}
}

export class Client {
	constructor(private readonly transport: RpcTransport) {
		this.Ipc = new IpcService(this.transport);
	}

  	route(msg: string): void { this.transport.dispatchMessage(msg); }
  	Ipc: IpcService;

}
