"use strict";

import mqtt from 'async-mqtt';

class TTNAppServer {
	get connection_string() {
		return `${this.settings.ttn.tls ? "mqtts" : "mqtt"}://${this.settings.ttn.host}:${this.settings.ttn.port}/`
	}
	
	// Destructure the awilix container
	constructor({ settings, ansi, MessageHandler, log }) {
		this.settings = settings;
		/** @type {Ansi} */
		this.a = ansi;
		/** @type {Log} */
		this.log = log;
		/** @type {MessageHandler} */
		this.message_handler = MessageHandler;
	}
	
	async run() {
		// 1: Sanity checks
		if(this.settings.ttn.app_id == "CHANGE_THIS" || this.settings.ttn.access_key == "CHANGE_THIS") {
			this.log.error(`Error: No TTN app id specified. Try filling in the required values in settings.toml. If they don't exist yet, try using server/settings.default.toml as a reference.`);
			return false;
		}
		
		if(this.settings.ttn.devices.includes("CHANGE_THIS")) {
			this.log.error(`Error: No device names specified. Try filling in the required values in settings.toml. If they don't exist yet, try using server/settings.default.toml as a reference.`);
			return false;
		}
		
		
		// 2: Connect
		this.ttn_client = await this.connect();
		this.ttn_client.on("message", this.handle_message.bind(this));
		this.log.log(`[mqtt] Connected to ${this.connection_string}`);
		
		
		// 3: Subscribe
		let result = await this.ttn_client.subscribe(this.settings.ttn.devices.map(
			(device_name) => `${this.settings.ttn.app_id}/devices/${device_name}/up`
		));
		
		this.log.log(`[mqtt] Subscribed to ${result.map((el) => el.topic).join(", ")}`);
	}
	
	connect() {
		return new Promise((resolve, _reject) => {
			let client = mqtt.connect(this.connection_string, {
				username: this.settings.ttn.app_id,
				password: this.settings.ttn.access_key
			});
			client.once("connect", () => resolve(client));
		});
	}
	
	async handle_message(topic, message_buffer) {
		let message = message_buffer.toString("utf8"),
			message_object = null;
		try {
			message_object = JSON.parse(message);
		} catch(error) {
			this.log.log(error);
			return false;
		}
		
		this.log.log(`[mqtt/handler] Got message from ${topic}`);
		await this.message_handler.handle(message_object);
	}
}

export default TTNAppServer;