import { browser, Runtime } from "webextension-polyfill-ts";
import { Communicator, commandList, commandFunction } from "../communicator";
import { newPromise } from "../utils";

interface BackgroundCommands extends commandList {
	translationFinished: TranslationMessage;
	languageList: LanguageListMessage;
}

interface ContentScriptCommands extends commandList {
	translationRequest: TranslationRequest;
}

interface TranslationMessage extends commandFunction {
	args: Translation;
}

interface LanguageListMessage extends commandFunction {
	args: Array<Language>;
}

interface TranslationRequest extends commandFunction {
	args: string;
}

export class BackgroundMessenger extends Communicator<
	BackgroundCommands,
	ContentScriptCommands
> {
	conn: Promise<Runtime.Port>;
	private resolvConn: (p: Runtime.Port) => void;
	constructor() {
		super();

		[this.conn, this.resolvConn] = newPromise<Runtime.Port>();

		browser.runtime.onConnect.addListener((p) => {
			if (p.name != "gtranslate_scraper_conn") return;
			this.resolvConn(p);
			p.onDisconnect.addListener(
				() => ([this.conn, this.resolvConn] = newPromise<Runtime.Port>())
			);
			p.onMessage.addListener((m) => this.onMessage(m, p.sender!));
		});
	}

	async runCommand<K extends keyof ContentScriptCommands>(
		command: K,
		args: ContentScriptCommands[K]["args"]
	) {
		const msg = this.getCommandMessage(command, args);
		(await this.conn).postMessage(msg);
	}
}

export class ContentScriptMessenger extends Communicator<
	ContentScriptCommands,
	BackgroundCommands
> {
	conn: Runtime.Port;
	constructor() {
		super();
		this.conn = browser.runtime.connect({
			name: "gtranslate_scraper_conn",
			// eslint-disable-next-line @typescript-eslint/no-explicit-any
		} as any); //The declaration file is wrong
		this.conn.onMessage.addListener((m) => this.onMessage(m));
	}
	async runCommand<K extends keyof BackgroundCommands>(
		command: K,
		args: BackgroundCommands[K]["args"]
	) {
		const msg = this.getCommandMessage(command, args);
		return this.conn.postMessage(msg);
	}
}