var Connections: Connections = {
	elements: {
		connectionbrowser: document.querySelector('.connectionbrowser'),

		table: document.querySelector('.connectedtable'),

		dialog: {
			container: document.querySelector('.connectiondialog'),
			dialog: document.querySelector('.connectiondialog').querySelector('.dialog'),
			fields: document.querySelector('.connectiondialog').querySelector('.fields'),
			message: document.querySelector('.connectiondialog').querySelector('.message'),
			link: document.querySelector('.connectiondialog').querySelector('.link'),
			cancel: document.querySelector('.connectiondialog').querySelector('.cn'),
			connect: document.querySelector('.connectiondialog').querySelector('.co')
		}
	},

	init() {
		Connections.elements.connectionbrowser.querySelectorAll('.available').forEach((item: HTMLDivElement) => {
			var integrationID = item.getAttribute('integrationID');
			var connectionType = item.getAttribute('connectionType');
			var button: HTMLDivElement = item.querySelector('.button');
			button.onclick = () => Connections.requestNewDevice(integrationID, connectionType);
		});
	},

	requestNewDevice(integrationID: string, connectionType: string) {
		socket.emit(
			'connections',
			'request',
			integrationID,
			connectionType,
			(connectionRequestData: ConnectionRequestData) => {
				if (connectionRequestData.fields && connectionRequestData.fields.length > 0)
					Connections.openDialog(integrationID, connectionType, connectionRequestData);
				else UndeckedNotification('Unable to add a new device of this type.', 'error', 5000);
			}
		);
	},

	openDialog(integrationID, connectionType, connectionRequestData: ConnectionRequestData) {
		Connections.elements.dialog.fields.innerHTML = '';

		var nameField: Connection_Field = {
			id: '_internal_name',
			name: 'Connection Name',
			type: 'text'
		};
		connectionRequestData.fields = [
			nameField,
			...connectionRequestData.fields
		];

		if (connectionRequestData.message != undefined) {
			Connections.elements.dialog.message.style.display = 'block';
			Connections.elements.dialog.message.innerText = connectionRequestData.message;
		} else Connections.elements.dialog.message.style.display = 'none';

		if (connectionRequestData.link != undefined) {
			Connections.elements.dialog.link.style.display = 'inline-block';
			Connections.elements.dialog.link.innerText = connectionRequestData.link.title;
			Connections.elements.dialog.link.href = connectionRequestData.link.address;
		} else Connections.elements.dialog.link.style.display = 'none';

		connectionRequestData.fields.forEach((field) => {
			var fieldcontainer = ce('div', [
				'field',
				`field_${field.id}`
			]);
			Connections.elements.dialog.fields.appendChild(fieldcontainer);

			var label = ce('div', 'fieldlabel', null, `${field.name}`);
			fieldcontainer.appendChild(label);

			var input: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement = null;

			switch (field.type) {
				case 'number':
				case 'text':
					input = <HTMLInputElement>ce('input', 'input', { type: field.type, fieldID: field.id });
					if (field.value != undefined) input.value = field.value;
					fieldcontainer.appendChild(input);
					break;
				case 'select':
					input = <HTMLInputElement>ce('select', 'input', { fieldID: field.id });
					if (field.values != undefined && field.values.length > 0)
						for (let i = 0; i < field.values.length; i++) {
							var option = ce('option', null, { value: field.values[i].id }, field.values[i].text);
							if (field.value != undefined && field.values[i].id == field.value)
								option.setAttribute('selected', '');
							input.appendChild(option);
						}

					fieldcontainer.appendChild(input);
					break;
			}
		});

		Connections.elements.dialog.cancel.onclick = Connections.closeDialog;
		Connections.elements.dialog.connect.onclick = () => {
			var properties = {};
			var inputs: NodeListOf<HTMLInputElement> = Connections.elements.dialog.fields.querySelectorAll('.input');
			for (let i = 0; i < inputs.length; i++)
				if (inputs[i].hasAttribute('fieldID')) properties[inputs[i].getAttribute('fieldID')] = inputs[i].value;

			Connections.elements.dialog.dialog.style.display = 'none';
			socket.emit(
				'connections',
				'create',
				integrationID,
				connectionType,
				properties,
				(succeed: boolean, errormessage?: string) => {
					if (succeed == true) {
						Connections.closeDialog();
					} else {
						Connections.elements.dialog.dialog.style.display = 'block';
						UndeckedNotification(
							errormessage != undefined ? errormessage : 'Unable to validate connection',
							'error',
							5000
						);
					}
				}
			);
		};

		Connections.elements.dialog.dialog.style.display = 'block';
		Connections.elements.dialog.container.style.display = 'flex';
	},

	closeDialog() {
		Connections.elements.dialog.container.style.display = 'none';
	},

	renderConnected(connectList: ConnectedList[]) {
		var table = Connections.elements.table;

		for (let i = 0; i < connectList.length; i++) {
			var connected = connectList[i];
			if (table.querySelector(`tr[connectionid="${connected.connectionID}"]`) == null) {
				var row = ce('tr', null, { connectionID: connected.connectionID });
				var status = ce('td', 'status');
				var statuscontainer = ce('div', 'statuscontainer');
				statuscontainer.appendChild(
					ce('div', [
						'value',
						'online'
					])
				);
				status.appendChild(statuscontainer);
				row.appendChild(status);
				row.appendChild(ce('td', 'name', null, connected.name));
				row.appendChild(ce('td', 'integration', null, connected.integrationName));
				row.appendChild(ce('td', 'type', null, connected.connectionType));
				table.appendChild(row);
			}
		}
	}
};
Connections.init();

interface Connections {
	elements: {
		connectionbrowser: HTMLDivElement;
		table: HTMLTableElement;

		dialog: {
			container: HTMLDivElement;
			dialog: HTMLDivElement;
			message: HTMLDivElement;
			link: HTMLAnchorElement;
			fields: HTMLDivElement;
			cancel: HTMLDivElement;
			connect: HTMLDivElement;
		};
	};

	init: () => void;
	requestNewDevice: (integrationID: string, connectionType: string) => void;
	openDialog: (integrationID, connectionID, connectionRequestData: ConnectionRequestData) => void;
	closeDialog: () => void;
	renderConnected: (connectList: ConnectedList[]) => void;
}

interface Connection_Field {
	id: string;
	name: string;
	type: 'text' | 'number' | 'select';
	values?: { id: string; text: string }[];
	value?: string;
}

interface ConnectedList {
	connectionID: string;
	integrationName: string;
	connectionType: string;
	name: string;
	online: boolean;
}

interface ConnectionRequestData {
	fields: Connection_Field[];
	message?: string;
	link?: { address: string; title: string };
}
