import { MorphFeature } from 'morphux';
import { Main } from './main';
import {
	formatUptime,
	ServiceState,
	setStatusState,
	StatusType,
} from './utils';

const CELCIUS = 'ºC';

export class DashboardCameraRunner {
	private _Main: Main;

	container: HTMLDivElement = document.querySelector(
		'.ntsh_dashboard-camerarunner'
	);

	connectionStatus: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-connectionstatus'
	);
	connectionInfo: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-connectioninfo'
	);
	rebootButton: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-reboot'
	);

	processStatus: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-processstatus'
	);
	processInfo: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-processinfo'
	);
	restartButton: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-restart'
	);

	uptimeInfo: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-uptime'
	);

	errorContainer: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-error'
	);
	errorText: HTMLDivElement = this.container.querySelector(
		'.ntsh_dashboard-camerarunner-errortext'
	);

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

		this.registerListeners();
	}

	updateState(state: CameraRunnerStatus) {
		// ----------- Connection -----------
		setStatusState(
			this.connectionStatus,
			{
				CONNECTING: 'yellow',
				CONNECTED: 'green',
				DISCONNECTED: 'red',
				FAILED: 'red',
			}[state.state] as StatusType
		);
		this.connectionInfo.innerText = state.message ?? '';

		// ----------- Process -----------
		if (state.state != 'CONNECTED') {
			state.processStatus.state = 'STOPPED';
			state.processStatus.message = 'Not connected';
			state.processStatus.startTime = -1;

			this.restartButton.style.display = 'none';
			this.rebootButton.style.display = 'none';
		} else {
			this.rebootButton.style.display = 'flex';

			if (state.processStatus.state == 'RUNNING')
				this.restartButton.style.display = 'flex';
			else this.restartButton.style.display = 'none';
		}

		setStatusState(
			this.processStatus,
			{
				RUNNING: 'green',
				STOPPED: 'gray',
				STARTING: 'yellow',
				PROBLEM: 'red',
			}[state.processStatus.state] as StatusType
		);
		this.processInfo.innerText = state.processStatus.message ?? '';

		// ----------- Uptime -----------
		const uptimeSeconds =
			state.processStatus.startTime == -1
				? -1
				: (Date.now() - state.processStatus.startTime) / 1000;
		this.uptimeInfo.innerText = formatUptime(uptimeSeconds);

		// ----------- Error -----------
		const errors: string[] = [];
		if ((state?.error ?? '').trim().length > 0) errors.push(state.error);
		if ((state?.processStatus?.error ?? '').trim().length > 0)
			errors.push(state.processStatus.error);
		if (errors.length > 0) {
			this.errorText.innerText = errors.join('\n');
			this.errorContainer.style.display = 'block';
		} else {
			this.errorContainer.style.display = 'none';
			this.errorText.innerText = '';
		}

		this._Main.Logs.setCameraLogs(state.processStatus.output.current);
	}

	registerListeners() {
		this._Main.socket.on(
			'cameraRunnerState',
			(state: CameraRunnerStatus) => {
				this.updateState(state);
			}
		);

		this.restartButton.addEventListener('click', async () => {
			this.executeCommand(
				'restart',
				'Are you sure you want to restart the Camera Runner process?'
			);
		});

		this.rebootButton.addEventListener('click', async () => {
			this.executeCommand(
				'reboot',
				'Are you sure you want to reboot the Camera Runner machine?'
			);
		});
	}

	private async executeCommand(command: string, message: string) {
		const confirmed = await MorphFeature.Confirm({
			title: 'Are you sure?',
			message,
		});
		if (!confirmed) return;

		MorphFeature.Loader({
			active: true,
			message: `Requesting Camera Runner ${command}...`,
		});
		this._Main.socket.emit(
			'cameraRunner',
			command,
			(response: { succeed: boolean; message?: string }) => {
				MorphFeature.Loader({ active: false });

				if (!response.succeed)
					return MorphFeature.Alert({
						title: 'Error',
						message: response.message,
					});

				MorphFeature.Notification({
					level: 'success',
					message: `Camera Runner is ${command}ing...`,
				});
			}
		);
	}
}

interface CameraRunnerStatus {
	state: ServiceState;
	message?: string;
	error?: string;

	processStatus: ProcessStatus;
}

export type ProcessStatusState = 'RUNNING' | 'STOPPED' | 'STARTING' | 'PROBLEM';

interface ProcessStatusSimple {
	state: ProcessStatusState;
	message?: string;
	error?: string;
}
interface ProcessStatus extends ProcessStatusSimple {
	startTime: number;
	output: { current: string[]; last: string[] };
}
