import { join } from 'path';
import { WebServer } from './WebServer/WebServer';
import { homedir } from 'os';
import {
	Config,
	ConfigurationManager,
} from './Configuration/ConfigurationManager';
import { CameraRunner } from './CameraRunner';
import { StartOrigin, UnityRunner } from './Unity/UnityRunner';
import { UnityWebSocket } from './Unity/UnityWebSocket';
import { TwilioHandler } from './Twilio';
import { delay } from './Utils';
import * as ping from 'ping';
import { shutdown } from './Shutdown';
import { Timer } from './Configuration/Timer';
import { Status } from './Status';
import { AudioChecker } from './Audio';

const PREFIX = '[Main]';
export class Main {
	dataPath = join(homedir(), 'MorphixProductions', 'NTSHControl');

	ConfigurationManager = new ConfigurationManager(this);
	Timer = new Timer(this);
	Status = new Status(this);
	WebServer = new WebServer(this);
	Twilio = new TwilioHandler(this);
	Audio = new AudioChecker(this);

	CameraRunner = new CameraRunner(this);
	UnityRunner = new UnityRunner(this);
	UnityWebSocket = new UnityWebSocket(this);

	Config: Config;

	async start() {
		await this.ConfigurationManager.load();

		await this.waitForRouter();

		await this.WebServer.listen();
		await this.Twilio.load();

		await this.Audio.waitForDevice();

		await this.CameraRunner.connect();

		await this.Timer.load();

		if ((this.Config.unity.launchOnStartup ?? true) === true)
			setTimeout(() => {
				this.UnityRunner.start(StartOrigin.Startup);
			}, this.Config.unity.executable.startUpDelay ?? 0);
		else {
			this.UnityRunner.setInfo(
				'Not set to launch on startup. Waiting for timer or manual start...',
				null,
				'STOPPED',
			);
		}
	}

	async restart() {
		console.log('Stopping UnityRunner...');
		await this.UnityRunner.stop();

		const doReboot = !process.argv.includes('--no-reboot');
		console.log(`${doReboot ? 'Rebooting' : 'Restarting'} CameraRunner...`);
		const succeed = await new Promise((resolve) => {
			this.CameraRunner.sendCommand(
				doReboot ? 'reboot' : 'restart',
				(response: { succeed: boolean; message?: string }) => {
					if (!response.succeed) {
						console.error(
							'Failed to reboot CameraRunner:',
							response.message,
						);
						this.Twilio.sendError(
							'CameraRunner',
							`Failed to reboot CameraRunner: ${response.message}`,
						);
						resolve(false);
					} else {
						console.log('CameraRunner rebooted successfully.');
						this.Twilio.sendError('CameraRunner', null);
						resolve(true);
					}
				},
			);
		});
		if (!succeed) return;

		await delay(5000);

		console.log('Starting UnityRunner...');
		await this.UnityRunner.start(this.UnityRunner.startOrigin);

		console.log('Restart complete.');
	}

	async shutdown() {
		console.log('Stopping UnityRunner...');
		await this.UnityRunner.stop();

		const doShutdown = process.argv.includes('--no-shutdown')
			? false
			: true;
		if (doShutdown) {
			console.log('Shutting down system...');
			shutdown();
		} else {
			console.log('Shutdown skipped due to --no-shutdown flag.');
		}

		process.exit(0);
	}

	waitForRouter() {
		if (this.Config.router?.waitForStartup !== true) return;
		return new Promise<void>((resolve) => {
			const check = () => {
				console.log(PREFIX, 'Waiting for router...');
				ping.sys.probe(this.Config.router.ip, async ({ alive }) => {
					if (alive) {
						console.log(PREFIX, 'Router is online');
						await delay(3000);
						return resolve();
					}

					await delay(1000);
					check();
				});
			};
			check();
		});
	}
}
