'use strict';


define('forum/chats', [
	'components',
	'translator',
	'mousetrap',
	'forum/chats/recent',
	'forum/chats/search',
	'forum/chats/messages',
	'benchpress',
	'composer/autocomplete',
	'hooks',
], function (components, translator, mousetrap, recentChats, search, messages, Benchpress, autocomplete, hooks) {
	var Chats = {
		initialised: false,
	};

	var newMessage = false;

	Chats.init = function () {
		var env = utils.findBootstrapEnvironment();

		if (!Chats.initialised) {
			Chats.addSocketListeners();
			Chats.addGlobalEventListeners();
		}

		recentChats.init();

		Chats.addEventListeners();
		Chats.resizeMainWindow();

		if (env === 'md' || env === 'lg') {
			Chats.addHotkeys();
		}

		$(document).ready(function () {
			hooks.fire('action:chat.loaded', $('.chats-full'));
		});

		Chats.initialised = true;
		messages.scrollToBottom($('.expanded-chat ul.chat-content'));

		search.init();

		if (ajaxify.data.hasOwnProperty('roomId')) {
			components.get('chat/input').focus();
		}
	};

	Chats.addEventListeners = function () {
		Chats.addSendHandlers(ajaxify.data.roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]'));
		Chats.addPopoutHandler();
		Chats.addActionHandlers(components.get('chat/messages'), ajaxify.data.roomId);
		Chats.addMemberHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="members"]'));
		Chats.addRenameHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="rename"]'));
		Chats.addLeaveHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="leave"]'));
		Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content'));
		Chats.addScrollBottomHandler($('.chat-content'));
		Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]'));
		Chats.addIPHandler($('[component="chat/main-wrapper"]'));
		Chats.createAutoComplete($('[component="chat/input"]'));

		$('[data-action="close"]').on('click', function () {
			Chats.switchChat();
		});
	};

	Chats.addIPHandler = function (container) {
		container.on('click', '.chat-ip-button', function () {
			var ipEl = $(this).parent();
			var mid = ipEl.parents('[data-mid]').attr('data-mid');
			socket.emit('modules.chats.getIP', mid, function (err, ip) {
				if (err) {
					return app.alertError(err);
				}
				ipEl.html(ip);
			});
		});
	};

	Chats.addPopoutHandler = function () {
		$('[data-action="pop-out"]').on('click', function () {
			var text = components.get('chat/input').val();
			var roomId = ajaxify.data.roomId;

			if (app.previousUrl && app.previousUrl.match(/chats/)) {
				ajaxify.go('user/' + ajaxify.data.userslug + '/chats', function () {
					app.openChat(roomId, ajaxify.data.uid);
				}, true);
			} else {
				window.history.go(-1);
				app.openChat(roomId, ajaxify.data.uid);
			}

			$(window).one('action:chat.loaded', function () {
				components.get('chat/input').val(text);
			});
		});
	};

	Chats.addScrollHandler = function (roomId, uid, el) {
		var loading = false;
		el.off('scroll').on('scroll', function () {
			messages.toggleScrollUpAlert(el);
			if (loading) {
				return;
			}

			var top = (el[0].scrollHeight - el.height()) * 0.1;
			if (el.scrollTop() >= top) {
				return;
			}
			loading = true;
			var start = parseInt(el.children('[data-mid]').length, 10);
			socket.emit('modules.chats.getMessages', {
				roomId: roomId,
				uid: uid,
				start: start,
			}, function (err, data) {
				if (err) {
					return app.alertError(err.message);
				}
				if (!data) {
					loading = false;
					return;
				}
				data = data.filter(function (chatMsg) {
					return !$('[component="chat/message"][data-mid="' + chatMsg.messageId + '"]').length;
				});
				if (!data.length) {
					loading = false;
					return;
				}
				messages.parseMessage(data, function (html) {
					var currentScrollTop = el.scrollTop();
					var previousHeight = el[0].scrollHeight;
					html = $(html);
					el.prepend(html);
					html.find('.timeago').timeago();
					html.find('img:not(.not-responsive)').addClass('img-responsive');
					el.scrollTop((el[0].scrollHeight - previousHeight) + currentScrollTop);
					loading = false;
				});
			});
		});
	};

	Chats.addScrollBottomHandler = function (chatContent) {
		chatContent.parent()
			.find('[component="chat/messages/scroll-up-alert"]')
			.off('click').on('click', function () {
				messages.scrollToBottom(chatContent);
			});
	};

	Chats.addCharactersLeftHandler = function (parent) {
		var element = parent.find('[component="chat/input"]');
		element.on('change keyup paste', function () {
			messages.updateRemainingLength(parent);
		});
	};

	Chats.addActionHandlers = function (element, roomId) {
		element.on('click', '[data-action]', function () {
			var messageId = $(this).parents('[data-mid]').attr('data-mid');
			var action = this.getAttribute('data-action');

			switch (action) {
				case 'edit':
					var inputEl = $('[data-roomid="' + roomId + '"] [component="chat/input"]');
					messages.prepEdit(inputEl, messageId, roomId);
					break;

				case 'delete':
					messages.delete(messageId, roomId);
					break;

				case 'restore':
					messages.restore(messageId, roomId);
					break;
			}
		});
	};

	Chats.addHotkeys = function () {
		mousetrap.bind('ctrl+up', function () {
			var activeContact = $('.chats-list .bg-info');
			var prev = activeContact.prev();

			if (prev.length) {
				Chats.switchChat(prev.attr('data-roomid'));
			}
		});
		mousetrap.bind('ctrl+down', function () {
			var activeContact = $('.chats-list .bg-info');
			var next = activeContact.next();

			if (next.length) {
				Chats.switchChat(next.attr('data-roomid'));
			}
		});
		mousetrap.bind('up', function (e) {
			if (e.target === components.get('chat/input').get(0)) {
				// Retrieve message id from messages list
				var message = components.get('chat/messages').find('.chat-message[data-self="1"]').last();
				if (!message.length) {
					return;
				}
				var lastMid = message.attr('data-mid');
				var inputEl = components.get('chat/input');

				messages.prepEdit(inputEl, lastMid, ajaxify.data.roomId);
			}
		});
	};

	Chats.addMemberHandler = function (roomId, buttonEl) {
		var modal;

		buttonEl.on('click', function () {
			app.parseAndTranslate('partials/modals/manage_room', {}, function (html) {
				modal = bootbox.dialog({
					title: '[[modules:chat.manage-room]]',
					message: html,
				});

				modal.attr('component', 'chat/manage-modal');

				Chats.refreshParticipantsList(roomId, modal);
				Chats.addKickHandler(roomId, modal);

				var searchInput = modal.find('input');
				var errorEl = modal.find('.text-danger');
				require(['autocomplete', 'translator'], function (autocomplete, translator) {
					autocomplete.user(searchInput, function (event, selected) {
						errorEl.text('');
						socket.emit('modules.chats.addUserToRoom', {
							roomId: roomId,
							username: selected.item.user.name,
						}, function (err) {
							if (err) {
								translator.translate(err.message, function (translated) {
									errorEl.text(translated);
								});
							}

							Chats.refreshParticipantsList(roomId, modal);
							searchInput.val('');
						});
					});
				});
			});
		});
	};

	Chats.addKickHandler = function (roomId, modal) {
		modal.on('click', '[data-action="kick"]', function () {
			var uid = parseInt(this.getAttribute('data-uid'), 10);

			socket.emit('modules.chats.removeUserFromRoom', {
				roomId: roomId,
				uid: uid,
			}, function (err) {
				if (err) {
					return app.alertError(err.message);
				}

				Chats.refreshParticipantsList(roomId, modal);
			});
		});
	};

	Chats.addLeaveHandler = function (roomId, buttonEl) {
		buttonEl.on('click', function () {
			bootbox.confirm({
				size: 'small',
				title: '[[modules:chat.leave]]',
				message: '<p>[[modules:chat.leave-prompt]]</p><p class="help-block">[[modules:chat.leave-help]]</p>',
				callback: function (ok) {
					if (ok) {
						socket.emit('modules.chats.leave', roomId, function (err) {
							if (err) {
								app.alertError(err.message);
							}

							// Return user to chats page. If modal, close modal.
							var modal = buttonEl.parents('.chat-modal');
							if (modal.length) {
								require(['chat'], function (chatLib) {
									chatLib.close(modal);
								});
							} else {
								ajaxify.go('chats');
							}
						});
					}
				},
			});
		});
	};

	Chats.refreshParticipantsList = function (roomId, modal) {
		socket.emit('modules.chats.getUsersInRoom', { roomId: roomId }, function (err, users) {
			var listEl = modal.find('.list-group');

			if (err) {
				return translator.translate('[[error:invalid-data]]', function (translated) {
					listEl.find('li').text(translated);
				});
			}

			app.parseAndTranslate('partials/modals/manage_room_users', {
				users: users,
			}, function (html) {
				listEl.html(html);
			});
		});
	};

	Chats.addRenameHandler = function (roomId, buttonEl, roomName) {
		var modal;

		buttonEl.on('click', function () {
			app.parseAndTranslate('partials/modals/rename_room', {
				name: roomName || ajaxify.data.roomName,
			}, function (html) {
				modal = bootbox.dialog({
					title: '[[modules:chat.rename-room]]',
					message: html,
					buttons: {
						save: {
							label: '[[global:save]]',
							className: 'btn-primary',
							callback: submit,
						},
					},
				});
			});
		});

		function submit() {
			socket.emit('modules.chats.renameRoom', {
				roomId: roomId,
				newName: modal.find('#roomName').val(),
			}, function (err) {
				if (err) {
					return app.alertError(err.message);
				}
			});
		}
	};

	Chats.addSendHandlers = function (roomId, inputEl, sendEl) {
		inputEl.off('keypress').on('keypress', function (e) {
			if (e.which === 13 && !e.shiftKey) {
				messages.sendMessage(roomId, inputEl);
				return false;
			}
		});

		sendEl.off('click').on('click', function () {
			messages.sendMessage(roomId, inputEl);
			inputEl.focus();
			return false;
		});
	};

	Chats.createAutoComplete = function (element) {
		if (!element.length) {
			return;
		}

		var data = {
			element: element,
			strategies: [],
			options: {
				style: {
					'z-index': 20000,
					flex: 0,
					top: 'inherit',
				},
				placement: 'top',
			},
		};

		hooks.fire('chat:autocomplete:init', data);
		if (data.strategies.length) {
			autocomplete.setup(data);
		}
	};

	Chats.leave = function (el) {
		var roomId = el.attr('data-roomid');
		socket.emit('modules.chats.leave', roomId, function (err) {
			if (err) {
				return app.alertError(err.message);
			}
			if (parseInt(roomId, 10) === parseInt(ajaxify.data.roomId, 10)) {
				ajaxify.go('user/' + ajaxify.data.userslug + '/chats');
			} else {
				el.remove();
			}
			require(['chat'], function (chat) {
				var modal = chat.getModal(roomId);
				if (modal.length) {
					chat.close(modal);
				}
			});
		});
	};

	Chats.switchChat = function (roomid) {
		// Allow empty arg for return to chat list/close chat
		if (!roomid) {
			roomid = '';
		}

		var url = 'user/' + ajaxify.data.userslug + '/chats/' + roomid + window.location.search;
		if (self.fetch) {
			fetch(config.relative_path + '/api/' + url, { credentials: 'include' })
				.then(function (response) {
					if (response.ok) {
						response.json().then(function (payload) {
							app.parseAndTranslate('partials/chats/message-window', payload, function (html) {
								components.get('chat/main-wrapper').html(html);
								html.find('.timeago').timeago();
								Chats.resizeMainWindow();
								ajaxify.data = payload;
								Chats.setActive();
								Chats.addEventListeners();
								hooks.fire('action:chat.loaded', $('.chats-full'));
								messages.scrollToBottom($('.expanded-chat ul.chat-content'));
								if (history.pushState) {
									history.pushState({
										url: url,
									}, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + url);
								}
							});
						});
					} else {
						console.warn('[search] Received ' + response.status);
					}
				})
				.catch(function (error) {
					console.warn('[search] ' + error.message);
				});
		} else {
			ajaxify.go(url);
		}
	};

	Chats.addGlobalEventListeners = function () {
		$(window).on('resize', Chats.resizeMainWindow);
		$(window).on('mousemove keypress click', function () {
			if (newMessage && ajaxify.data.roomId) {
				socket.emit('modules.chats.markRead', ajaxify.data.roomId);
				newMessage = false;
			}
		});
	};

	Chats.addSocketListeners = function () {
		socket.on('event:chats.receive', function (data) {
			if (parseInt(data.roomId, 10) === parseInt(ajaxify.data.roomId, 10)) {
				newMessage = data.self === 0;
				data.message.self = data.self;

				messages.appendChatMessage($('.expanded-chat .chat-content'), data.message);
			} else if (ajaxify.data.template.chats) {
				var roomEl = $('[data-roomid=' + data.roomId + ']');

				if (roomEl.length > 0) {
					roomEl.addClass('unread');
				} else {
					var recentEl = components.get('chat/recent');
					app.parseAndTranslate('partials/chats/recent_room', {
						rooms: {
							roomId: data.roomId,
							lastUser: data.message.fromUser,
							usernames: data.message.fromUser.username,
							unread: true,
						},
					}, function (html) {
						recentEl.prepend(html);
					});
				}
			}
		});

		socket.on('event:user_status_change', function (data) {
			app.updateUserStatus($('.chats-list [data-uid="' + data.uid + '"] [component="user/status"]'), data.status);
		});

		messages.addSocketListeners();

		socket.on('event:chats.roomRename', function (data) {
			var roomEl = components.get('chat/recent/room', data.roomId);
			var titleEl = roomEl.find('[component="chat/title"]');
			ajaxify.data.roomName = data.newName;

			titleEl.text(data.newName);
		});
	};

	Chats.resizeMainWindow = function () {
		var viewportHeight = $(window).height();
		var mainWrapper = components.get('chat/main-wrapper');
		var navWrapper = components.get('chat/nav-wrapper');
		var fromTop = 0;
		if (mainWrapper.length && navWrapper.length) {
			fromTop = mainWrapper.offset().top || navWrapper.offset().top;
		}

		$('.chats-full').height(viewportHeight - fromTop - 1);

		Chats.setActive();
	};

	Chats.setActive = function () {
		if (ajaxify.data.roomId) {
			socket.emit('modules.chats.markRead', ajaxify.data.roomId);
			$('[data-roomid="' + ajaxify.data.roomId + '"]').toggleClass('unread', false);
			$('.expanded-chat [component="chat/input"]').focus();
		}
		$('.chats-list li').removeClass('bg-info');
		$('.chats-list li[data-roomid="' + ajaxify.data.roomId + '"]').addClass('bg-info');

		components.get('chat/nav-wrapper').attr('data-loaded', ajaxify.data.roomId ? '1' : '0');
	};


	return Chats;
});
