import { pathExistsSync, readJSONSync, writeFile } from 'fs-extra';
import { Main } from './Main';
import { join } from 'path';

const PREFIX = '[Audio]';
export class AudioChecker {
	private _Main: Main;

	private configPath: string;

	deviceName: string = null;

	constructor(Main: Main) {
		this._Main = Main;

		this.configPath = join(this._Main.dataPath, 'audio.json');
		this.load();
	}

	async waitForDevice() {
		let portAudio;
		try {
			portAudio = require('naudiodon');
		} catch (error) {
			console.warn(
				PREFIX,
				'Failed to load naudiodon, skipping audio check. Please install it to enable audio features.',
			);
			return;
		}

		if ((this.deviceName ?? '').trim().length == 0) {
			console.log(
				PREFIX,
				'No audio device configured, skipping audio check. Available devices:',
			);

			portAudio
				.getDevices()
				.filter((device) => device.maxOutputChannels > 0)
				.forEach((device) => {
					console.log(` - ${device.name}`);
				});
			return;
		}

		console.log(PREFIX, `Waiting for device "${this.deviceName}"...`);

		let counter = 0;
		return new Promise<void>((resolve) => {
			const c = setInterval(() => {
				counter++;
				const availableDevices = portAudio
					.getDevices()
					.filter((device) => device.maxOutputChannels > 0)
					.map((device) => device.name);

				if (!availableDevices.includes(this.deviceName)) {
					if (counter == 3) {
						console.log(
							PREFIX,
							'Trouble finding the correct device. Available devices:',
						);
						availableDevices.forEach((device) => {
							console.log(` - ${device}`);
						});
					}
					return;
				}

				const hostApis = portAudio.getHostAPIs();
				const defaultOutputDeviceId =
					hostApis.HostAPIs[hostApis.defaultHostAPI].defaultOutput;
				const defaultOutputDeviceName = portAudio
					.getDevices()
					.find(
						(device) => device.id === defaultOutputDeviceId,
					)?.name;
				if (defaultOutputDeviceName !== this.deviceName) {
					console.warn(
						PREFIX,
						`The configured device "${this.deviceName}" is not set as the default output device. Please set it as the default output device to ensure proper functionality. Current default output device: "${defaultOutputDeviceName}".`,
					);
					this._Main.Twilio.sendError(
						'Audio',
						`The configured device "${this.deviceName}" is not set as the default output device. Current default output device: "${defaultOutputDeviceName}".`,
					);
					return;
				}

				clearInterval(c);
				resolve();
				console.log(PREFIX, `Device "${this.deviceName}" is ready!`);
			}, 1000);
		});
	}

	load() {
		console.log(PREFIX, 'Loading audio configuration...');
		const exists = pathExistsSync(this.configPath);
		if (!exists) return this.save();

		const data = readJSONSync(this.configPath);
		this.deviceName = data.deviceName;
	}

	private _save: NodeJS.Timeout;
	async save() {
		if (this._save) clearTimeout(this._save);

		this._save = setTimeout(async () => {
			writeFile(
				this.configPath,
				JSON.stringify(
					{ deviceName: this.deviceName ?? null },
					null,
					4,
				),
			);
		}, 1000);
	}
}
