'use strict';

const coreClass = require("../core");

const async = require("async");
const fs = require("fs");

let tasks = {};

module.exports = class extends coreClass {
	initialize() {
		return new Promise((resolve, reject) => {
			this.setStage(1);
			
			this.cache = this.moduleManager.modules["cache"];
			this.stations = this.moduleManager.modules["stations"];
			this.notifications = this.moduleManager.modules["notifications"];
			this.utils = this.moduleManager.modules["utils"];

			//this.createTask("testTask", testTask, 5000, true);
			this.createTask("stationSkipTask", this.checkStationSkipTask, 1000 * 60 * 30);
			this.createTask("sessionClearTask", this.sessionClearingTask, 1000 * 60 * 60 * 6);
			this.createTask("logFileSizeCheckTask", this.logFileSizeCheckTask, 1000 * 60 * 60);

			resolve();
		});
	}

	async createTask(name, fn, timeout, paused = false) {
		try { await this._validateHook(); } catch { return; }

		tasks[name] = {
			name,
			fn,
			timeout,
			lastRan: 0,
			timer: null
		};
		if (!paused) this.handleTask(tasks[name]);
	}

	async pauseTask(name) {
		try { await this._validateHook(); } catch { return; }

		if (tasks[name].timer) tasks[name].timer.pause();
	}

	async resumeTask(name) {
		try { await this._validateHook(); } catch { return; }

		tasks[name].timer.resume();
	}

	async handleTask(task) {
		try { await this._validateHook(); } catch { return; }

		if (task.timer) task.timer.pause();
		
		task.fn.apply(this, [
			() => {
				task.lastRan = Date.now();
				task.timer = new this.utils.Timer(() => {
					this.handleTask(task);
				}, task.timeout, false);
			}
		]);
	}

	/*testTask(callback) {
		//Stuff
		console.log("Starting task");
		setTimeout(() => {
			console.log("Callback");
			callback();
		}, 10000);
	}*/

	async checkStationSkipTask(callback) {
		this.logger.info("TASK_STATIONS_SKIP_CHECK", `Checking for stations to be skipped.`, false);
		async.waterfall([
			(next) => {
				this.cache.hgetall('stations', next);
			},
			(stations, next) => {
				async.each(stations, (station, next2) => {
					if (station.paused || !station.currentSong || !station.currentSong.title) return next2();
					const timeElapsed = Date.now() - station.startedAt - station.timePaused;
					if (timeElapsed <= station.currentSong.duration) return next2();
					else {
						this.logger.error("TASK_STATIONS_SKIP_CHECK", `Skipping ${station._id} as it should have skipped already.`);
						this.stations.initializeStation(station._id);
						next2();
					}
				}, () => {
					next();
				});
			}
		], () => {
			callback();
		});
	}

	async sessionClearingTask(callback) {
		this.logger.info("TASK_SESSION_CLEAR", `Checking for sessions to be cleared.`, false);
		async.waterfall([
			(next) => {
				this.cache.hgetall('sessions', next);
			},
			(sessions, next) => {
				if (!sessions) return next();
				let keys = Object.keys(sessions);
				async.each(keys, (sessionId, next2) => {
					let session = sessions[sessionId];
					if (session && session.refreshDate && (Date.now() - session.refreshDate) < (60 * 60 * 24 * 30 * 1000)) return next2();
					if (!session) {
						this.logger.info("TASK_SESSION_CLEAR", 'Removing an empty session.');
						this.cache.hdel('sessions', sessionId, () => {
							next2();
						});
					} else if (!session.refreshDate) {
						session.refreshDate = Date.now();
						this.cache.hset('sessions', sessionId, session, () => {
							next2();
						});
					} else if ((Date.now() - session.refreshDate) > (60 * 60 * 24 * 30 * 1000)) {
						this.utils.socketsFromSessionId(session.sessionId, (sockets) => {
							if (sockets.length > 0) {
								session.refreshDate = Date.now();
								this.cache.hset('sessions', sessionId, session, () => {
									next2()
								});
							} else {
								this.logger.info("TASK_SESSION_CLEAR", `Removing session ${sessionId} for user ${session.userId} since inactive for 30 days and not currently in use.`);
								this.cache.hdel('sessions', session.sessionId, () => {
									next2();
								});
							}
						});
					} else {
						this.logger.error("TASK_SESSION_CLEAR", "This should never log.");
						next2();
					}
				}, () => {
					next();
				});
			}
		], () => {
			callback();
		});
	}

	async logFileSizeCheckTask(callback) {
		this.logger.info("TASK_LOG_FILE_SIZE_CHECK", `Checking the size for the log files.`);
		async.each(
			["all.log", "debugStation.log", "error.log", "info.log", "success.log"],
			(fileName, next) => {
				const stats = fs.statSync(`${__dirname}/../../log/${fileName}`);
				const mb = stats.size / 1000000;
				if (mb > 25) return next(true);
				else next();
			},
			(err) => {
				if (err === true) {
					this.logger.error("LOGGER_FILE_SIZE_WARNING", "************************************WARNING*************************************");
					this.logger.error("LOGGER_FILE_SIZE_WARNING", "***************ONE OR MORE LOG FILES APPEAR TO BE MORE THAN 25MB****************");
					this.logger.error("LOGGER_FILE_SIZE_WARNING", "****MAKE SURE TO REGULARLY CLEAR UP THE LOG FILES, MANUALLY OR AUTOMATICALLY****");
					this.logger.error("LOGGER_FILE_SIZE_WARNING", "********************************************************************************");
				}
				callback();
			}
		);
	}
}