const EventEmitter = require('events');

const bus = new EventEmitter();

module.exports = class {
	constructor(name, moduleManager) {
		this.name = name;
		this.moduleManager = moduleManager;
		this.lockdown = false;
		this.dependsOn = [];
		this.eventHandlers = [];
		this.state = "NOT_INITIALIZED";
		this.stage = 0;
		this.lastTime = 0;
		this.totalTimeInitialize = 0;
		this.timeDifferences = [];
		this.failed = false;
	}

	_initialize() {
		this.logger = this.moduleManager.modules["logger"];
		this.setState("INITIALIZING");

		this.initialize().then(() => {
			this.setState("INITIALIZED");
			this.setStage(0);
			this.moduleManager.printStatus();
		}).catch(async (err) => {
			if (this.moduleManager.fancyConsole) {
				this.moduleManager.replaceLoggerWithConsole();
			}
			
			this.failed = true;

			console.error(`${this.logger.colors.FgRed}MODULE FAILED! Module ${this.name} has failed!${this.logger.colors.Reset}`);
			console.error(err);

			if (this.moduleManager.fancyConsole) {
				for(let i = 0; i < this.logger.reservedLines; i++) {
					process.stdout.write(`\n`);
				}
			}

			this.moduleManager.aModuleFailed(this);
		});
	}

	_onInitialize() {
		return new Promise(resolve => bus.once(`stateChange:${this.name}:INITIALIZED`, resolve));
	}

	_isInitialized() {
		return new Promise(resolve => {
			if (this.state === "INITIALIZED") resolve();
		});
	}

	_isNotLocked() {
		return new Promise((resolve, reject) => {
			if (this.state === "LOCKDOWN") reject();
			else resolve();
		});
	}

	setState(state) {
		this.state = state;
		bus.emit(`stateChange:${this.name}:${state}`);
		this.logger.info(`MODULE_STATE`, `${state}: ${this.name}`);
	}

	setStage(stage) {
		if (stage !== 1)
			this.totalTimeInitialize += (Date.now() - this.lastTime);
		//this.timeDifferences.push(this.stage + ": " + (Date.now() - this.lastTime) + "ms");
		this.timeDifferences.push(Date.now() - this.lastTime);

		this.lastTime = Date.now();
		this.stage = stage;
		this.moduleManager.printStatus();
	}

	_validateHook() {
		return Promise.race([this._onInitialize, this._isInitialized]).then(
			() => this._isNotLocked()
		);
	}

	_lockdown() {
		this.lockdown = true;
		this.setState("LOCKDOWN");
		this.moduleManager.printStatus();
	}
}