import { ServerAuth } from "/js/connect/auth.js";

function randint(min, max) {
	return Math.ceil((Math.random() * (max - min)) + min);
}

function getTraceId() {
	const dict = "1234567890abcdefABCDEF";
	return [...new Array(16)]
		.map(() => dict[randint(0, dict.length - 1)])
		.join("");
}

class ProtoApiMethods {
	constructor (api) {
		this.api = api;
	}
	
	async _protoMethod (rqdata, threadcb) {
		const socket = this.api.socket;
		const trace_id = getTraceId()
		
		const promise = new Promise((rs, rj) => {
			socket.onmessage = (ev) => {
				ev = JSON.parse(ev.data);
				const data = ev.result;
				return rs(data);
				if (ev.trace_id === trace_id)
					if (!!ev.ended)
						return rs(data);
					threadcb(data);
			};
			socket.onerror = (err) => rj(err);
		});
		socket.send(
			JSON.stringify({ trace_id, ...rqdata }),
		);
		return await promise;
	}
}

class ApiMethods extends ProtoApiMethods {
	async _protoMethod (rqdata) {
		throw new Error("_protoMethod allowed only into abstract class");
	}
	
	constructor (api) {
		super(api);
	}
	
	async info () {
		return await super._protoMethod({
			method: "info",
		});
	}
	
	async authed () {
		return await super._protoMethod({
			method: "authed",
		});
	}
}

class ApiHTML {
	constructor (api) {
		this.api = api;
	}
	
	async renderAuth (authMode) {
		switch (authMode) {
			default:
				document.getElementById("server.area").innerHTML = '<div class="auth-window"><button>connect</button></div>';
		}
	}
}

export class ApiSocket {
	constructor ({
		isTLSmode, address, port
	}) {
		this.tlsMode = isTLSmode;
		this.address = address;
		this.port = port;
		
		this.socket = new WebSocket(`${!isTLSmode ? "ws" : "wss"}://${address}:${port}`);
		this.methods = new ApiMethods(this);
		
		this.html = new ApiHTML(this);
	}
	
	async run () {
		const socket = this.socket;
		const promise = new Promise((rs, rj) => {
			socket.onopen = () => this.methods.info().then(data => rs(data));
			socket.onerror = (err) => rj(err);
		});
		return await promise;
	}
}